【发布时间】:2011-08-29 15:16:26
【问题描述】:
数据库是带有 MyISAM 引擎的 MySQL。
表定义:
CREATE TABLE IF NOT EXISTS matches (
id int(11) NOT NULL AUTO_INCREMENT,
game int(11) NOT NULL,
user int(11) NOT NULL,
opponent int(11) NOT NULL,
tournament int(11) NOT NULL,
score int(11) NOT NULL,
finish tinyint(4) NOT NULL,
PRIMARY KEY ( id ),
KEY game ( game ),
KEY user ( user ),
KEY i_gfu ( game , finish , user )
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=3149047 ;
我已经在(game, finish, user) 上设置了一个索引,但是这个GROUP BY 查询仍然需要 0.4 - 0.6 秒才能运行:
SELECT user AS player
, COUNT( id ) AS times
FROM matches
WHERE finish = 1
AND game = 19
GROUP BY user
ORDER BY times DESC
EXPLAIN 输出:
| id | select_type | table | type | possible_keys | key | key_len |
| 1 | SIMPLE | matches | ref | game,i_gfu | i_gfu | 5 |
| ref | rows | Extra |
| const,const | 155855 | Using where; Using temporary; Using filesort |
有什么方法可以让它更快吗?该表有大约 80 万条记录。
编辑:我将COUNT(id) 更改为COUNT(*),时间下降到 0.08 - 0.12 秒。我想我在创建索引之前已经尝试过了,但之后又忘记了。
在解释输出中,Using index解释了加速:
| rows | Extra |
| 168029 | Using where; Using index; Using temporary; Using filesort |
(附带问题:下降 5 倍正常吗?)
大约有2000个用户,所以最终的排序,即使使用filesort,也不会影响性能。我尝试不使用ORDER BY,但仍然需要几乎相同的时间。
【问题讨论】:
-
count(*) 的性能比 count(id) 快得多的原因是 MySQL 对 count(*) 情况进行了特定优化。 count(id) 案例第二次遍历数据以检索结果,其中 count(*) 使用现有的内部行计数器。尽可能使用 count(*)。
标签: mysql group-by query-optimization myisam