代码之家  ›  专栏  ›  技术社区  ›  Sebastian Breit

优化的sql查询比未优化的查询慢吗?[关闭]

  •  1
  • Sebastian Breit  · 技术社区  · 7 年前

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

    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;
    

    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;
    

    在此之前,一切看起来都很好,两个查询都返回相同的结果集。问题是 第二个查询的执行时间是第一个查询的三倍 . 怎么可能呢? 谢谢

    1 回复  |  直到 7 年前
        1
  •  1
  •   spencer7593    7 年前

    这些查询明显不同。(我们假设失踪者 FROM 第一个版本的子查询中的关键字是将其放入问题中的结果,并且原始查询没有相同的语法错误。还有,提到 b.id SELECT bb.id ... 但我们只是猜测。)

    如果两个查询返回的结果集完全相同,则这是数据中的情况。(我们可以演示两个查询结果不同的数据集。)

    “缩短”查询不一定优化它。

    真正重要的(在性能方面)是执行计划。也就是说,正在执行什么操作,按什么顺序执行,以及使用大表时,哪些索引可用并正在使用。

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

    建议:使用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
                      )
    

    (假设我们保证子查询返回的值永远不会为空…)

    可以重新写成 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
    

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

    问题中的重写不能保证返回等效结果。