【发布时间】:2019-08-17 21:37:52
【问题描述】:
我有一个具有以下结构的表,几乎有 120000 行,
desc user_group_report
+------------------+----------+------+-----+-------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------------+----------+------+-----+-------------------+-------+
| user_id | int | YES | MUL | NULL | |
| group_id | int(11) | YES | MUL | NULL | |
| type_id | int(11) | YES | | NULL | |
| group_desc | varchar(128)| NO| | NULL |
| status | enum('open','close')|NO| | NULL | |
| last_updated | datetime | NO | | CURRENT_TIMESTAMP | |
+------------------+----------+------+-----+-------------------+-------+
我在以下键上有索引:
- user_group_type(user_id,group_id,group_type)
- group_type(group_id,type_id)
- user_type(user_id,type_id)
- user_group(user_id,group_id)
我的问题是我在上面的表组上按 group_id 运行 count(*) 聚合,并在 type_id 上有一个子句
这里是查询:
select count(*) user_count, group_id
from user_group_report
where type_id = 1
group by group_id;
这里是解释计划(查询平均需要 0.3 秒):
+----+-------------+------------------+-------+---------------------------------+---------+---------+------+--------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------------+-------+---------------------------------+---------+---------+------+--------+--------------------------+
| 1 | SIMPLE | user_group_report | index | user_group_type,group_type,user_group | group_type | 10 | NULL | 119811 | Using where; Using index |
+----+-------------+------------------+-------+---------------------------------+---------+---------+------+--------+--------------------------+
据我了解,由于索引复杂,查询几乎会进行全表扫描,并且当我尝试在 group_id 上添加索引时,解释计划中的行数显示较少(几乎是行数的一半),但花费的时间查询执行时间增加到 0.4-0.5 秒。
我尝试了不同的方法来添加/删除索引,但它们都没有减少所花费的时间。
假设表结构不能更改并且查询独立于其他表,有人可以建议我一个更好的方法来优化上述查询或者如果我在这里遗漏任何东西。
PS: 我已经尝试将查询修改为以下内容,但找不到任何改进。
select count(user_id) user_count, group_id
from user_group_report
where type_id = 1
group by group_id;
感谢任何帮助。
编辑:
根据建议,我添加了一个新索引
type_group on (type_id,group_id)
这是新的解释计划。 explain中的行数减少了,但是查询执行时间还是一样的
+----+-------------+------------------+------+---------------------------------+---------+---------+-------+-------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------------+------+---------------------------------+---------+---------+-------+-------+--------------------------+
| 1 | SIMPLE | user_group_report | ref | user_group_type,type_group,user_group | type_group | 5 | const | 59846 | Using where; Using index |
+----+-------------+------------------+------+---------------------------------+---------+---------+-------+-------+--------------------------+
编辑 2: 按照 answers/cmets 中的建议添加详细信息
select count(*)
from user_group_report
where type_id = 1
这个查询本身需要 0.25 秒来执行。
这里是解释计划:
+----+-------------+------------------+------+---------------+---------+---------+-------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------------+------+---------------+---------+---------+-------+-------+-------------+
| 1 | SIMPLE | user_group_report | ref | type_group | type_group | 5 | const | 59866 | Using index |
+----+-------------+------------------+------+---------------+---------+---------+-------+-------+-------------+
【问题讨论】:
-
count(user_id)可能比count(*)慢,因为它会检查user_id是否不是NULL。 -
PRIMARY KEY是什么?请提供SHOW CREATE TABLE,它比DESC更具描述性。
标签: mysql sql query-optimization aggregation sql-query-store