如何加快多内连接查询?

时间:2016-06-15 06:33:30

标签: mysql sql

我有两张桌子。第一个表(用户)是一个简单的" id,用户名" 100,00行,第二个(统计数据)是" id,date,stat"有20M行。

我试图弄清楚哪个用户名在统计信息中上升最多,这是我的查询。在功能强大的计算机上,此查询需要几分钟才能完成。是否有更好的方法来编写它以加快速度?

SELECT a.id, a.username, b.stat, c.stat, (b.stat - c.stat) AS stat_diff
FROM users AS a
INNER JOIN stats AS b ON (b.id=a.id)
INNER JOIN stats AS c ON (c.id=a.id)
WHERE b.date = '2016-01-10'
AND c.date = '2016-01-13'
GROUP BY a.id
ORDER BY stat_diff DESC
LIMIT 100

我试过的另一种方式,但它似乎并不是最佳的

SELECT a.id, a.username, 
     (SELECT b.stat FROM stats AS b ON (b.id=a.id) AND b.date = '2016-01-10') AS start,
     (SELECT c.stat FROM stats AS c ON (c.id=a.id) AND c.date = '2016-01-14') AS end,
     ((SELECT b.stat FROM stats AS b ON (b.id=a.id) AND b.date = '2016-01-10') - 
      (SELECT c.stat FROM stats AS c ON (c.id=a.id) AND c.date = '2016-01-14')) AS stat_diff
FROM users AS a
GROUP BY a.id
ORDER BY stat_diff DESC
LIMIT 100

3 个答案:

答案 0 :(得分:0)

查询似乎没问题,验证您的索引..

或者 试试这个查询

SELECT a.id, a.username, b.stat, c.stat, (b.stat - c.stat) AS stat_diff
FROM users AS a
INNER JOIN (select id,stat from stats where date = '2016-01-10') AS b ON (b.id=a.id)
INNER JOIN (select id,stat from stats where date = '2016-01-13') AS c ON (c.id=a.id)
GROUP BY a.id
ORDER BY stat_diff DESC
LIMIT 100

答案 1 :(得分:0)

您需要做的就是帮助优化器。最低限度。有一个如下所示的检查清单

1.我的连接列是否已编入索引?
2.在哪里条款Sargable
3.是否存在任何隐含的,明确的转换 4.我看到任何统计问题

另一个有趣的方面是你的数据是如何分配的,一旦你理解了数据,你就能够代表执行计划并根据你的需要改变它

<强> EX: 想想我有100个客户表,每个至少有10个订单(总计高达10000个订单)。现在如果你只需要按日期查找前三个订单,你不希望扫描发生订单表

现在在你的情况下,我可能不会选择第二个选项,即使优化器也可以为这个选择一个好的计划,我会先进入并尝试查看执行时间是否可接受。如果不是我将通过我的检查清单并尝试进一步调整

答案 2 :(得分:0)

<强>简介

让我们假设我们重写这样的句子:

SELECT a.id, a.username, b.stat, c.stat, (b.stat - c.stat) AS stat_diff
FROM users AS a
INNER JOIN stats AS b ON 
    b.date = STR_TO_DATE('2016-01-10', '%Y-%m-%d' ) and b.id=a.id
INNER JOIN stats AS c ON 
    c.date = STR_TO_DATE('2016-01-13', '%Y-%m-%d' ) and c.id=a.id
GROUP BY a.id
ORDER BY stat_diff DESC
LIMIT 100

我们确保:

  • users表在字段id上有索引:
  • stats包含复合字段date的索引,idcreate index stats_idx_d_i on stats ( date, id );

,然后

数据库优化器可以使用索引来选择受限制的日期集('RSD'),这意味着匹配已过滤日期的行。这很快。

<强>但是

您按计算字段排序:

 (b.stat - c.stat) AS stat_diff   #<-- calculated 
 ORDER BY stat_diff DESC          #<-- this forces to calculate it

这种类型无法进行优化,因为您应该逐一计算'RSD'(受限制的数据集)的所有结果。

<强>结论

问题是,'RSD'上的行数怎么样?如果它们只有几百行,那么查询可能会快速运行,否则,您的查询将会很慢。

无论如何,你应该确保查询的第一步(没有排序)是由索引而不是全扫描。使用Explain命令确保。