Ken*_*Ken 5 mysql nhibernate innodb distinct primary-key
我的应用程序做了相当多的事情之一是:
select count(distinct id) from x;
Run Code Online (Sandbox Code Playgroud)
使用id表的主键x.使用MySQL 5.1(和5.0),它看起来像这样:
mysql> explain SELECT count(distinct id) from x;
+----+-------------+----------+-------+---------------+-----------------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+-------+---------------+-----------------+---------+------+---------+-------------+
| 1 | SIMPLE | x | index | NULL | ix_blahblahblah | 1 | NULL | 1234567 | Using index |
+----+-------------+----------+-------+---------------+-----------------+---------+------+---------+-------------+
Run Code Online (Sandbox Code Playgroud)
在InnoDB上,这并不是很酷,但它也不错.
本周我正在尝试使用MySQL 5.5.11,并且惊讶地发现相同的查询速度慢很多倍.启动缓存后,与之前的5秒相比,大约需要90秒.该计划现在看起来像这样:
mysql> explain select count(distinct id) from x;
+----+-------------+----------+-------+---------------+---------+---------+------+---------+-------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+-------+---------------+---------+---------+------+---------+-------------------------------------+
| 1 | SIMPLE | x | range | NULL | PRIMARY | 4 | NULL | 1234567 | Using index for group-by (scanning) |
+----+-------------+----------+-------+---------------+---------+---------+------+---------+-------------------------------------+
Run Code Online (Sandbox Code Playgroud)
让它再次快速运行的一种方法是使用select count(id) from x,这是安全的,因为它id是一个主键,但我正在经历一些抽象层(如NHibernate),这使得这是一个非常重要的任务.
我试过analyze table x但它没有产生任何明显的差异.
它看起来有点像这个bug,虽然不清楚适用的版本是什么,或者发生了什么(没有人在一年内触及它,但它是"严重/高/高").
除了简单地改变我的查询之外,还有什么办法可以让MySQL变得更聪明吗?
更新:
根据要求,这是一种或多或少重现它的方法.我编写了这个SQL脚本来生成100万行虚拟数据(需要10或15分钟才能运行):
delimiter $$
drop table if exists x;
create table x (
id integer unsigned not null auto_increment,
a integer,
b varchar(100),
c decimal(9,2),
primary key (id),
index ix_a (a),
index ix_b (b),
index ix_c (c)
) engine=innodb;
drop procedure if exists fill;
create procedure fill()
begin
declare i int default 0;
while i < 1000000 do
insert into x (a,b,c) values (1,"one",1.0);
set i = i+1;
end while;
end$$
delimiter ;
call fill();
Run Code Online (Sandbox Code Playgroud)
当它完成后,我会观察到这种行为:
select count(distinct id) from x
select count(id) from x
select count(distinct id) from x
select count(id) from x
编辑:
如果我通过说修改5.5中的查询
select count(distinct id) from x force index (ix_a);
Run Code Online (Sandbox Code Playgroud)
它运行得更快.索引b和c也有效(在不同程度上),甚至强制索引也有PRIMARY帮助.
我不保证这会更好,但作为一种可能的解决方法,您可以尝试:
SELECT COUNT(*)
FROM (SELECT id
FROM x
GROUP BY id) t
Run Code Online (Sandbox Code Playgroud)