无论如何,该查询都需要执行表扫描或索引扫描,因此它必须以任何一种方式访问16M个条目.
在创建了一个包含16M行的表之后,我测试了查询的解释.
mysql> explain select person, concat((sum(qa_flag)/count(*))*100, '%')
-> from myTable
-> group by person;
+----+-------------+---------+------------+-------+---------------+--------+---------+------+----------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+-------+---------------+--------+---------+------+----------+----------+-------+
| 1 | SIMPLE | myTable | NULL | index | person | person | 129 | NULL | 16329623 | 100.00 | NULL |
+----+-------------+---------+------------+-------+---------------+--------+---------+------+----------+----------+-------+
这显示了一个索引扫描(type: index
),估计的"行"计数为~16M(在索引扫描的情况下,这实际上不是行数,而是索引叶条目).
一种可能的优化是创建一个同时具有person
和qa_flag
的新索引,以用作覆盖索引.这样,它可以生成只读取索引的结果,而不会触及表行.
mysql> alter table mytable add key (person, qa_flag);
Query OK, 0 rows affected (22.11 sec)
mysql> explain select person, concat((sum(qa_flag)/count(*))*100, '%')
-> from myTable
-> group by person;
+----+-------------+---------+------------+-------+-----------------+----------+---------+------+----------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+-------+-----------------+----------+---------+------+----------+----------+-------------+
| 1 | SIMPLE | myTable | NULL | index | person,person_2 | person_2 | 131 | NULL | 16329623 | 100.00 | Using index |
+----+-------------+---------+------------+-------+-----------------+----------+---------+------+----------+----------+-------------+
这仍然会对大约16M个索引项进行索引扫描,但这是一个轻微的改进,因为在额外的字段中添加了"Using index"注释.
我try 执行该查询.考虑到它必须判断多少个索引条目,它很快就完成了:
mysql> select person, concat((sum(qa_flag)/count(*))*100, '%') from myTable group by person limit 2;
+----------------------------------+------------------------------------------+
| person | concat((sum(qa_flag)/count(*))*100, '%') |
+----------------------------------+------------------------------------------+
| 0000023f507999464aa2b78875b7e5d6 | 0.0000% |
...
| fffffe98d0963d27015c198262d97221 | 0.0000% |
+----------------------------------+------------------------------------------+
16777216 rows in set (8.64 sec)
(我将Person值生成为一串随机散列.)
我正在一台搭载M1 CPU的Macbook Pro笔记本电脑上进行测试.我使用带有默认配置的MySQL 8.0.32.这不是一次超高性能的测试.
所以我猜还有其他因素阻碍了你的表现.您的硬件严重过时,或者服务器超载,或者您的客户端应用程序以某种方式阻止了您.
我建议您仔细判断数据库服务器上的负载.
还可以使用query profiling来获取查询时间的更多详细信息.我知道您说查询需要一个多小时,但是您应该能够通过在行数较少的表上进行测试来获得完成的查询.