【问题标题】:Two queries faster than than one?两个查询比一个查询快?
【发布时间】:2011-09-26 14:03:31
【问题描述】:

我有一个带有列的表格:

CREATE TABLE aggregates (
    a VARHCAR,
    b VARCHAR,
    c VARCHAR,
    metric INT
    KEY test (a, b, c, metric)
);

如果我进行如下查询:

SELECT b, c, SUM(metric) metric
FROM aggregates
WHERE a IN ('a', 'couple', 'of', 'values')
GROUP BY b, c
ORDER BY b, c

查询耗时10秒,解释为:

+----+-------------+------------+-------+---------------+------+---------+------+--------+-----------------------------------------------------------+
| id | select_type | table      | type  | possible_keys | key  | key_len | ref  | rows   | Extra                                                     |
+----+-------------+------------+-------+---------------+------+---------+------+--------+-----------------------------------------------------------+
|  1 | SIMPLE      | aggregates | range | test          | test | 767     | NULL | 582383 | Using where; Using index; Using temporary; Using filesort |
+----+-------------+------------+-------+---------------+------+---------+------+--------+-----------------------------------------------------------+

如果我还按 a 列分组/排序,所以它不需要临时/文件排序,但然后我自己在另一个查询中做同样的事情:

SELECT b, c, SUM(metric) metric
FROM (
    SELECT a, b, c, SUM(metric) metric
    FROM aggregates
    WHERE a IN ('a', 'couple', 'of', 'values')
    GROUP BY a, b, c
    ORDER BY a, b, c
) t
GROUP BY b, c
ORDER BY b, c

查询耗时 1 秒,解释为:

+----+-------------+------------+-------+---------------+------+---------+------+--------+---------------------------------+
| id | select_type | table      | type  | possible_keys | key  | key_len | ref  | rows   | Extra                           |
+----+-------------+------------+-------+---------------+------+---------+------+--------+---------------------------------+
|  1 | PRIMARY     | <derived2> | ALL   | NULL          | NULL | NULL    | NULL |    252 | Using temporary; Using filesort |
|  2 | DERIVED     | aggregates | range | test          | test | 767     | NULL | 582383 | Using where; Using index        |
+----+-------------+------------+-------+---------------+------+---------+------+--------+---------------------------------+

这是为什么?为什么我在单独的外部查询中进行分组而不是在一个单独的查询中进行分组会更快?

【问题讨论】:

  • 这两个查询是否显示相同的结果?您是否在第二次查询中忘记了metric?
  • 恕我直言,这很可能与 MySQL 的实现方式有关,在其他数据库引擎上可能无法像这样工作。
  • 你确定性能差异不仅仅是数据库缓存吗?
  • 第二个查询会在 MySQL 和任何其他 RDBMS 中引发错误。在“复制粘贴更改名称”期间出现了问题。
  • ypercube:是的,结果相同。对不起,我在简化时忘记了公制。它在那里,我会添加它。

标签: mysql performance optimization


【解决方案1】:

SQL 的工作方式是您在每个步骤中拥有的数据越少,查询执行的速度就越快。 因为您首先在内部查询中进行分组,所以您将摆脱外部查询不再需要处理的大量数据。

SQL optimisation 应该会回答您的一些问题。但要记住的最重要的事情是,您可以在查询早期消除的内容越多,查询运行的速度就越快。

还有一部分数据库会尝试不同的方式来运行查询。服务器的这部分大部分时间会选择最快的路径,但是在查询中更具体可以真正帮助它。 此页面上的更多信息:Readings In Database Systems

看看你的解释,似乎对如此大量的行进行文件排序可能会对查询造成很大的伤害。因为主查询(第二个查询的外部范围)中的行将在内存表中工作。

【讨论】:

    【解决方案2】:

    在第一种情况下,索引用于查找匹配记录,但不能用于排序,因为您没有在 group/order by 子句中包含最左边的列。我有兴趣查看这两个查询配置文件:

    设置分析=1;

    运行查询 1;

    运行查询 2;

    显示查询 1 的配置文件;

    显示查询 2 的配置文件;

    【讨论】:

    【解决方案3】:

    出于好奇,你可以试试这个版本吗?:

    SELECT b, c, SUM(metric) metric
    FROM aggregates
    WHERE a = 'some-value'
    GROUP BY b, c
    

    还有这个:

    SELECT b, c, metric
    FROM (
        SELECT a, b, c, SUM(metric) metric
        FROM aggregates
        WHERE a = 'some-value'
        GROUP BY a, b, c
    ) t
    ORDER BY b, c
    

    还有这个:

    SELECT b, c, SUM(metric) metric
    FROM aggregates
    WHERE a = 'some-value'
    GROUP BY a, b, c
    

    【讨论】:

    • 第一个:同样(慢)速度,第二个:快(当然,只有一行),第三个:快(当然,更多行)
    • Fwiw,按 (a, b, c) 分组​​返回 252 行,按 (b, c) 分组​​返回 83。
    • 很抱歉,但我看不出这是怎么发生的。您显然没有告诉我们整个故事,或者您没有正确翻译这些查询。我看不到第一个或第二个查询将如何返回 1 行。
    • 我不是说第一个只返回 1 行,但你说得对,我翻译了第二个错误。我们都会犯错误 :) (是的,当然,我并不是在讲述整个故事,而是在这里简化了很多查询)。
    • 还有更多行,因为我不是在做 = 'some-value',而是在做 IN (...)。这当然是相关的,我担心我可能遗漏了太多。我已经更新了问题。
    【解决方案4】:

    **** 已编辑:不好的答案,因为我没有看到 where 部分。

    我认为这只是在第二个查询中 MySQL 使用了索引,而第一个没有。 如果您创建像 (b, c, metric) 这样的索引,我很确定第一个查询会比第二个查询快。

    编辑得更详细:

    第一个查询:

    • 没有一个好的索引来执行查询。
    • 测试索引在 (a,b,c,metric) 上,您需要在 (b,c) 上建立索引((b,c,metric) 也可以)
    • 也许 MySQL 正在使用测试索引,但不是一个好的索引,所以就像全表扫描一样。

    第二次查询:

    • 正在使用索引 (a,b,c)
    • 在第二个实例上执行非索引查询,但数据比第一个查询少。

    【讨论】:

    • 两个查询都使用test 索引,如 EXPLAIN 输出所示。
    • 我不太相信解释。索引从“a”列开始,所以我看不出如何在没有“a”列的情况下应用于组。结果证实了我的理论:) (也许正在使用索引,但使用错误)
    • 查看此处了解如何在GROUP BY(紧密索引扫描)中使用索引:dev.mysql.com/doc/refman/5.1/en/group-by-optimization.html
    • 你是对的,我没有把注意力放在 where 子句上......我认为在你粘贴的链接中是答案:松散索引扫描是“处理 GROUP BY 的最有效方法” .因此,将GROUP BY b, c 更改为GROUP BY a, b, c 可能会更快。
    • 我也是这么想的,但是有SUM()的时候就不能使用松散索引扫描了。仅适用于 MIN() 和 MAX()。所以,这不是这里的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多