SQL-使用嵌套查询仍然可以快速计数吗?

时间:2018-11-13 17:49:08

标签: mysql sql performance database-performance

假设我有如下查询:

SELECT message.mid
FROM message
WHERE message.mid <= 100

据我所知,如果将查询更改为以下内容,由于未扩展列,它将执行得更快。

SELECT COUNT(message.mid)
FROM message
WHERE message.mid <= 100

但是下面的查询会有相同的好处吗?还会那么快吗?

SELECT COUNT(*)
FROM (
    SELECT message.mid,
           message.something,
           message.something2,
           message.something3,
    FROM message
    WHERE message.mid <= 100
) AS A

2 个答案:

答案 0 :(得分:2)

We can ask MySQL what it will do。这是5.7。

mysql> explain SELECT COUNT(*) FROM (     SELECT message.mid     FROM message     WHERE message.mid <= 100 
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
| id | select_type | table   | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra                    |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
|  1 | SIMPLE      | message | NULL       | range | PRIMARY       | PRIMARY | 4       | NULL |  100 |   100.00 | Using where; Using index |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)


mysql> explain SELECT count(message.mid)     FROM message     WHERE message.mid <= 100;
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
| id | select_type | table   | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra                    |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
|  1 | SIMPLE      | message | NULL       | range | PRIMARY       | PRIMARY | 4       | NULL |  100 |   100.00 | Using where; Using index |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)

看起来一样。 MySQL优化了子查询。

这是一个示例,说明我们在MySQL无法优化子查询的情况下看到的内容。

mysql> explain SELECT * FROM (     SELECT message.mid     FROM message where mid < 100 group by mid) m;
+----+-------------+------------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
| id | select_type | table      | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra                    |
+----+-------------+------------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
|  1 | PRIMARY     | <derived2> | NULL       | ALL   | NULL          | NULL    | NULL    | NULL |   99 |   100.00 | NULL                     |
|  2 | DERIVED     | message    | NULL       | range | PRIMARY       | PRIMARY | 4       | NULL |   99 |   100.00 | Using where; Using index |
+----+-------------+------------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+

"Optimizing Derived Tables and View References"举例说明了此优化的工作原理。

  

示例1:

SELECT * FROM (SELECT * FROM t1) AS derived_t1;
     

合并后,该查询的执行方式类似于:

SELECT * FROM t1;

该页面概述了MySQL用于提高子查询效率的其他许多优化技巧。

答案 1 :(得分:1)

COUNT(*)说要计算行数。

COUNT(x)表示对x IS NOT NULL处的行进行计数。因此,速度稍慢,并且答案可能有所不同。

SELECT mid(相对于SELECT COUNT(...))-速度慢且体积大。它返回的是mid的所有值,而不仅仅是一个数字。

SELECT COUNT(..) FROM ( SELECT ... )-慢得多(在旧的MySQL版本中),因为它必须使用子查询的结果生成一个临时表。另外,COUNT仅收集一个简单的数字;子查询正在收集很多行。

如果为mid编制了索引(包括PRIMARY KEY,则WHERE mid <= 100是对索引(或表)的“范围”扫描。也就是说,它仅触及部分行。

如果未为mid编制索引,则将扫描整个表格-因此速度较慢。