【问题标题】:Optimizing an SQL query with very large amounts of data使用大量数据优化 SQL 查询
【发布时间】:2016-09-13 09:08:27
【问题描述】:

首先要做的事情:我已经寻找过类似的问题,但没有发现任何东西可以解释为什么我正在做的事情是不好的做法,所以我发布了一个新问题,即使这是非常基本的问题。

我收到投诉说我对我们的数据库施加了太大的压力,但我不知道如何优化,所以我在这里寻求帮助。

我在底部附上了我正在处理的结构的图片。我想要做的是以下几点: 我需要获取执行特定 userAction 的人员列表(比如说“viewProduct”,然后添加有关该人的用户年龄、国家和大陆的信息。

我写了以下内容:

select  u.userId, u.userAge, c.countryName, co.name, ul.createdTime,
        ul.userAction
    from  user_log as ul
    left join  user as u  ON u.userId = ul.userId
    left join  country as c  ON c.id = u.userCountryId
    left join  continent as co  ON co.id = c.continentId
    where  ul.createdTime > '2016-06-01'
      and  u.userAge > 40
      and  (ul.userAction like 'viewProduct'
              or  ul.userAction like 'storeProduct'
              or  ul.userAction like 'addProduct'
           );

这显然不够好,所以我真诚地希望有人能够帮助解决如何提高效率。我不太习惯处理条目数以亿计的表格。

提前谢谢你!

db structure

【问题讨论】:

  • 您在joins 和where 中使用的列是否有索引?
  • 用户数据是每次都存在于所有四个表中还是取决于。根据您的搜索要求,您正在以不正确的方式在文本前后使用 % 符号。
  • 对于优化查询计划会很有帮助。一个问题是,您要加入的 ID 上是否有任何索引
  • WHERE 子句中包含u.userAge > 40 会使user 上的LEFT OUTER JOIN 成为INNER JOIN。也就是说,我猜你的数据结构是这样的,你可能想在任何地方使用INNER JOINS

标签: mysql sql optimization query-optimization


【解决方案1】:

查询中有几个问题:

  1. 如果您没有限制且没有索引 - MySQL 将检查来自 user_log 的所有 100000000 条记录以给出结果。要减少处理记录的数量,请将索引添加到“ul.createdTime”和“ul.userAction”。这甚至可以通过组合索引(createdTime、userAction)。
  2. “ul.userAction like 'viewProduct'”等于“ul.userAction = 'viewProduct'”。并且整个构造可以重构为“ul.userAction in ('viewProduct', 'storeProduct', 'addProduct')”
  3. 将“u.userAge > 40”移动到加入条件中。并且“u.userAge”上的索引也会有很大帮助。
  4. 我不确定,这取决于您的数据,但有时“inner join user as u”可能比“left join user as u”工作得更快。所以,你可以在这里玩。 (但查询逻辑会改变)

为包含 100000000 条记录的表添加索引是一项漫长的任务。因此,出于测试目的,我将仅复制最后 1000000 条记录的“user_log”并测量其性能。然后我会添加所有提到的索引并测试这个查询:

select u.userId, u.userAge, c.countryName, co.name, ul.createdTime,     ul.userAction 
from user_log as ul
left join user as u
    on u.userId = ul.userId and u.userAge > 40
left join country as c
    on c.id = u.userCountryId
left join continent as co
on co.id = c.continentId
where ul.createdTime > '2016-06-01' and 
ul.userAction in('viewProduct', 'storeProduct', 'addProduct');

.. 并比较性能。

请告诉我们,这对您有帮助吗?

【讨论】:

  • 翻转它——(userAction, createdTime)。索引使用停止在第一个“范围”(createdTime > ...)
  • 再次,从=开始,然后是范围:(userId, userAge)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-07
相关资源
最近更新 更多