我有一张包含 ~16M 记录的表。我正在尝试查询表以确定 - 对于每个独特的人 - 他们的记录中有多少百分比被标记在他们身上。大约有200个独特的人。我的查询是这样的:
select person, concat((sum(qa_flag)/count(*))*100, '%')
from myTable
group by person;
其中
qa_flag
是一个 1 或 null 的 tinyint 字段。 person
字段上有一个索引集,但 qa_flag
字段上没有。
此查询不会在任何合理时间内返回。我让它运行了一个小时。更糟糕的是,我需要动态查询并使用这些统计信息在网页上加载表格。
有人可以告诉我我做错了什么,或者如果我本身没有做错任何事,有人可以建议加快查询速度的方法 - 显着。
谢谢。
不管怎样,这个查询都需要进行表扫描或索引扫描,因此它必须以任何一种方式访问 16M 条目。
我在创建一个包含 1600 万行的表后为您的查询测试了 EXPLAIN。
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 索引条目进行索引扫描,但由于额外字段中的“使用索引”注释,它略有改进。
我尝试执行查询。考虑到它必须检查多少索引条目,它很快就完成了:
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)
(我将人的值生成为一堆随机哈希值。)
我正在使用 M1 CPU 的 Macbook Pro 笔记本电脑上进行测试。我使用默认配置的 MySQL 8.0.32。这不是超高性能测试
所以我想还有其他事情阻碍了你的表现。要么你的硬件严重过时,要么服务器超载,要么你的客户端应用程序以某种方式阻止了你。
我建议您仔细检查数据库服务器上的负载。
还使用 query profiling 来获取查询花费时间的更多详细信息。我知道您说过查询需要一个多小时,但是您应该能够通过在行数较少的表上进行测试来获得完成的查询。