【问题标题】:MySQL differences between aggregate order in query vs subqueryMySQL查询中的聚合顺序与子查询之间的差异
【发布时间】:2013-11-04 15:36:27
【问题描述】:

我有 2 个关于订购数据的查询:

查询 1:

SELECT  * FROM    (
    SELECT      idprovince, COUNT(*) total
    FROM        cities
    JOIN        persons USE INDEX (index_5) USING (idcity)
    WHERE       is_tutor = 'Y'
    GROUP BY    idprovince
) A
ORDER BY total DESC

查询 2:

SELECT      idprovince, COUNT(*) total
FROM        cities
JOIN        persons USE INDEX (index_5) USING (idcity)
WHERE       is_tutor = 'Y'
GROUP BY    idprovince
ORDER BY    total DESC

查询 1 返回数据比查询 2 快得多,我的问题是使用查询排序和在子查询中使用它有什么大的区别?

注意:我的数据库版本是 mysql-5.0.96-x64。个人数据量约为 40 万人,城市为 500 人。

更新: mysql解释命令的输出:

查询 1:

mysql> EXPLAIN
    -> SELECT  *
    -> FROM    (
    ->     SELECT      idprovince, COUNT(*) total
    ->     FROM        cities
    ->     JOIN        persons USE INDEX (index_5) USING (idcity)
    ->     WHERE       is_tutor = 'Y'
    ->     GROUP BY    idprovince
    -> ) A
    -> ORDER BY total DESC
    -> ;
+----+-------------+------------+--------+---------------+---------+---------+------------------------------------+--------+----------------------------------------------+
| id | select_type | table      | type   | possible_keys | key     | key_len | ref                                | rows   | Extra                                        |
+----+-------------+------------+--------+---------------+---------+---------+------------------------------------+--------+----------------------------------------------+
|  1 | PRIMARY     | <derived2> | ALL    | NULL          | NULL    | NULL    | NULL                               |     34 | Using filesort                               |
|  2 | DERIVED     | persons    | ref    | index_5       | index_5 | 2       |                                    | 163316 | Using where; Using temporary; Using filesort |
|  2 | DERIVED     | cities     | eq_ref | PRIMARY       | PRIMARY | 4       | _myproject_lesaja_2.persons.idcity |      1 |                                              |
+----+-------------+------------+--------+---------------+---------+---------+------------------------------------+--------+----------------------------------------------+
3 rows in set (1.22 sec)

查询 2:

mysql> EXPLAIN
    ->     SELECT      idprovince, COUNT(*) total
    ->     FROM        cities
    ->     JOIN        persons USE INDEX (index_5) USING (idcity)
    ->     WHERE       is_tutor = 'Y'
    ->     GROUP BY    idprovince
    ->     ORDER BY    total DESC;
+----+-------------+---------+-------+---------------+-------------+---------+-------+--------+----------------------------------------------+
| id | select_type | table   | type  | possible_keys | key         | key_len | ref   | rows   | Extra                                        |
+----+-------------+---------+-------+---------------+-------------+---------+-------+--------+----------------------------------------------+
|  1 | SIMPLE      | cities  | index | PRIMARY       | FK_cities_1 | 4       | NULL  |      4 | Using index; Using temporary; Using filesort |
|  1 | SIMPLE      | persons | ref   | index_5       | index_5     | 2       | const | 163316 | Using where                                  |
+----+-------------+---------+-------+---------------+-------------+---------+-------+--------+----------------------------------------------+
2 rows in set (0.00 sec)

结果查询一:

mysql> SELECT  *
    -> FROM    (
    ->     SELECT      idprovince, COUNT(*) total
    ->     FROM        cities
    ->     JOIN        persons USE INDEX (index_5) USING (idcity)
    ->     WHERE       is_tutor = 'Y'
    ->     GROUP BY    idprovince
    -> ) A
    -> ORDER BY total DESC
    -> ;
+------------+-------+
| idprovince | total |
+------------+-------+
|         35 | 15797 |
......................
......................
......................

|         76 |  2091 |
|         65 |  2018 |
+------------+-------+
34 rows in set (0.78 sec)

结果查询2:

mysql> SELECT      idprovince, COUNT(*) total
    -> FROM        cities
    -> JOIN        persons USE INDEX (index_5) USING (idcity)
    -> WHERE       is_tutor = 'Y'
    -> GROUP BY    idprovince
    -> ORDER BY    total DESC;
+------------+-------+
| idprovince | total |
+------------+-------+
|         35 | 15797 |
|         33 | 14413 |
|         12 | 13683 |
......................
......................
......................
|         34 |  2135 |
|         76 |  2091 |
|         65 |  2018 |
+------------+-------+
34 rows in set (8 min 25.80 sec)

显示配置文件输出: 问题 1:

+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000240 |
| Opening tables       | 0.000043 |
| System lock          | 0.000004 |
| Table lock           | 0.000392 |
| optimizing           | 0.000084 |
| statistics           | 0.004455 |
| preparing            | 0.000026 |
| Creating tmp table   | 0.000221 |
| executing            | 0.000002 |
| Copying to tmp table | 0.913722 |
| Sorting result       | 0.000065 |
| Sending data         | 0.000020 |
| removing tmp table   | 0.000145 |
| Sending data         | 0.000008 |
| init                 | 0.000017 |
| optimizing           | 0.000002 |
| statistics           | 0.000038 |
| preparing            | 0.000007 |
| executing            | 0.000001 |
| Sorting result       | 0.000012 |
| Sending data         | 0.000337 |
| end                  | 0.000002 |
| end                  | 0.000002 |
| query end            | 0.000002 |
| freeing items        | 0.000020 |
| closing tables       | 0.000001 |
| removing tmp table   | 0.000074 |
| closing tables       | 0.000003 |
| logging slow query   | 0.000001 |
| cleaning up          | 0.000003 |
+----------------------+----------+

问题 2:

+----------------------+------------+
| Status               |   Duration |
+----------------------+------------+
| starting             |   0.000195 |
| Opening tables       |   0.000029 |
| System lock          |   0.000004 |
| Table lock           |   0.000011 |
| init                 |   0.000078 |
| optimizing           |   0.000021 |
| statistics           |   0.003399 |
| preparing            |   0.000025 |
| Creating tmp table   |   0.000259 |
| Sorting for group    |   0.000007 |
| executing            |   0.000001 |
| Copying to tmp table | 506.711308 |
| Sorting result       |   0.000049 |
| Sending data         |   0.000298 |
| end                  |   0.000004 |
| removing tmp table   |   0.000150 |
| end                  |   0.000002 |
| end                  |   0.000002 |
| query end            |   0.000002 |
| freeing items        |   0.000013 |
| closing tables       |   0.000003 |
| logging slow query   |   0.000001 |
| logging slow query   |   0.000042 |
| cleaning up          |   0.000003 |
+----------------------+------------+

创建语句

CREATE TABLE persons (
    idperson INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    is_tutor ENUM('Y','N') NULL DEFAULT 'N',
    name VARCHAR(64) NOT NULL,
    ...
    idcity INT(10) UNSIGNED NOT NULL,
    ...
    PRIMARY KEY (idperson),
    UNIQUE INDEX index_3 (name) USING BTREE,
    UNIQUE INDEX index_4 (email) USING BTREE,
    INDEX index_5 (is_tutor),
    ...
    CONSTRAINT FK_persons_1 FOREIGN KEY (idcity) REFERENCES cities (idcity)
)
ENGINE=InnoDB
AUTO_INCREMENT=414738;

CREATE TABLE cities (
    idcity INT(10) UNSIGNED NOT NULL,
    idprovince INT(10) UNSIGNED NOT NULL,
    city VARCHAR(64) NOT NULL,
    PRIMARY KEY (idcity),
    UNIQUE INDEX index_3 (city),
    INDEX FK_cities_1 (idprovince),
    CONSTRAINT FK_cities_1 FOREIGN KEY (idprovince) REFERENCES provinces (idprovince)
)
ENGINE=InnoDB;

【问题讨论】:

  • EXPLAIN 输出有什么不同吗?
  • 我只是更新解释和结果。
  • @RaymondNijland 没有包含总列的表,它是查询计算的聚合。
  • @bramaningds 我还需要显示创建表结构..
  • @bramaningds 你也可以使用 SET profiling= 1 来分析你的查询吗?显示资料;和 SHOW PROFILE ALL FOR QUERY query_id 这样你就可以看到查询是 CPU 还是磁盘 I/O 有界

标签: mysql aggregate


【解决方案1】:

诚然,我不是这方面的专家,但查看ORDER BY 上的MySQL Documentation 优化,您的查询编号中不仅有一个而且有两个未优化的ORDER BY 使用2:

SELECT      idprovince, COUNT(*) total
FROM        cities
JOIN        persons USE INDEX (index_5) USING (idcity)
WHERE       is_tutor = 'Y'
GROUP BY    idprovince
ORDER BY    total DESC

第一个:

用于获取行的键

WHERE is_tutor = 'Y'

ORDER BY中使用的不一样:

ORDER BY total DESC

第二个:

您有不同的ORDER BYGROUP BY 表达式。

GROUP BY    idprovince
ORDER BY    total DESC

在上述两种情况下,MySQL 不会使用索引来解析ORDER BY,尽管它可以使用索引来搜索行以匹配WHERE 子句。

另一方面,您的 1 号查询遵循 ORDER BY 的优化形式,尽管在子查询之外使用了 ORDER BY

这可能是 Query No. 2 远比 Query No. 1 慢的原因。

此外,在这两种情况下,Index (idCity) 在解析 ORDER BY 时实际上也毫无用处,因为索引使用 idCityORDER BY 子句使用 Total,这是一个聚合结果。

另见讨论here

【讨论】:

  • 嗨。感谢您的回复。 'total' 是聚合函数,所以它不能使用索引进行排序。 Index_5 是 is_tutor 字段的索引。
  • @bramaningds 您能否为您的查询 1 显示配置文件?我可以看到您的 2 号查询复制到临时表在您的查询中消耗的时间最多。
  • 查询 1 大约需要 780 毫秒,所以我猜它对于所有配置文件都将低于 1 秒。现在,我在路上,12 小时后到家。我将尽快更新查询 1 的配置文件输出。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-12
  • 2020-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-18
相关资源
最近更新 更多