优化的 sql 查询比未优化的查询慢?

Optimized sql query is slower than not optimized one?

一位程序员同事向我展示了他创建的查询,如下所示:

SELECT a.row, b.row, c.row
FROM 
a LEFT JOIN
b ON (a.id = b.id) LEFT JOIN
c ON (c.otherid= b.otherid)
WHERE a.id NOT IN (SELECT DISTINCT b.id bb 
INNER JOIN
c cc ON (bb.a_id = cc.a_id)
WHERE (bb.date BETWEEN '2018-08-04 00:00:00' AND '2018-08-06 23:59:59'))
GROUP BY a.id ORDER BY c.otherid DESC;

所以我通过删除第二个查询并直接应用 WHERE 子句来缩短它:

SELECT a.row, b.row, c.row
FROM 
a LEFT JOIN
b ON (a.id = b.id) LEFT JOIN
c ON (c.otherid= b.otherid)
WHERE b.date NOT BETWEEN '2018-08-04 00:00:00' AND '2018-08-06 23:59:59'
GROUP BY a.id ORDER BY c.otherid DESC;

到这里为止,一切似乎都很好,并且两个查询 return 相同的结果集。问题是第二个查询的执行时间是第一个 的三倍。这怎么可能? 谢谢

查询明显不同。 (我们假设第一个版本的子查询中缺少 FROM 关键字是将其放入问题中的结果,并且原始查询没有相同的语法错误。此外,对子查询的 SELECT 列表中的 b.id 非常可疑,我们怀疑这确实是对 bb.id 的引用......但我们只是猜测。)

如果这两个查询 return 使用完全相同的结果集,那是数据中的一种情况。 (我们可以演示两个查询的结果不同的数据集。)

"Shortening"一个查询不一定优化它。

真正重要的(就性能而言)是执行计划。也就是说,正在执行什么操作,以什么顺序执行,并且 tables 很大,哪些索引可用和正在使用。

没有 table 和索引定义,不可能给出明确的诊断。

建议:使用MySQL EXPLAIN查看每个查询的执行计划


假设原始查询有一个 WHERE 形式的子句:

WHERE a.id NOT IN ( SELECT DISTINCT bb.id 
                      FROM b bb 
                      JOIN c cc
                        ON bb.a_id = cc.a_id
                     WHERE bb.date BETWEEN '2018-08-04 00:00:00' 
                                       AND '2018-08-06 23:59:59'
                       AND bb.id IS NOT NULL
                  )

(假设我们保证由子查询编辑的值 return 永远不会为 NULL...)

可以将其重写为 NOT EXISTS 相关子查询以获得等效结果:

  WHERE NOT EXISTS ( SELECT 1
                       FROM b bb
                       JOIN c cc
                         ON cc.a_id = bb.a_id
                      WHERE bb.date >= '2018-08-04 00:00:00'
                        AND bb.date <  '2018-08-07 00:00:00'
                        AND bb.id = a.id
                   )

或者可以重写为反连接

  LEFT 
  JOIN b bb 
    ON bb.id = a.id
   AND bb.date >= '2018-08-04 00:00:00'
   AND bb.date <  '2018-08-07 00:00:00'
  LEFT
  JOIN c cc
    ON cc.a_id = bb.a_id
 WHERE cc.a_id IS NULL

对于大型集合,需要提供适当的索引以获得最佳性能。

问题中提出的重写不能保证return 相同的结果。