2011-12-08 18 views
4

我有一个简单的表MySQL如何决定它是否使用GROUP BY索引?

stock_ledger_id INT(10) (Primary) 
piece_to_bin_id INT(10) 
quantity   INT(11) 
create_datetime TIMESTAMP 
... and a few VARCHARs 

一些简单的指标

Key_name   Cardinality 
PRIMARY    1510443 
piece_to_bin_id  100696 

这个简单的查询需要大约8秒钟:

SELECT piece_to_bin_id, 
     SUM(quantity), 
     MAX(create_datetime) 
FROM stock_ledger 
GROUP BY piece_to_bin_id 

这里的讲解:

id select_type table  type possible_keys key key_len ref rows Extra       
1 SIMPLE  stock_ledger ALL NULL   NULL NULL NULL 1512976 Using temporary; Using filesort 

我发现我可以通过强制的指标,使其下降到约0.5秒

SELECT piece_to_bin_id, 
     SUM(quantity), 
     MAX(create_datetime) 
FROM stock_ledger 
FORCE INDEX (piece_to_bin_id) 
GROUP BY piece_to_bin_id 

然后EXPLAIN看起来像这样:

id select_type table  type possible_keys key    key_len ref rows Extra 
1 SIMPLE  stock_ledger index NULL   piece_to_bin_id 4  NULL 1512976 

我使用的是MySQL 5.1.41 ,该表是MyISAM,我以前运行过ANALYZE TABLE。

所以,我坚持“MySQL再次错了,只是强制索引”或是有一个真正的原因,为什么MySQL使用全表扫描?也许我可以修复?

+1

两者几乎相同,仍然使用全表扫描。 – ajreal

+0

即使您使用'SQL_NO_CACHE'指令,您的第二个查询是否会在1秒内运行? ('SELECT SQL_NO_CACHE <查询的其余部分>') –

回答

1

无论如何,查询需要全表扫描,可能是因为mysql试图避免从键值和行的额外转换。查询可能会从复合(piece_to_ bin_id,create_datetime)索引或甚至(piece_to_ bin_id,create_datetime,quantity)中受益更多。后者将成为覆盖指数。

UPD

看来16X更快的结果来自于你的情况下,数据分布(可能是,由create_datetime排序相同piece_to_bin_id许多相邻行)。 MyISAM似乎使用索引来减少结果行的数量,因为使用它们意味着随机磁盘I/O操作。

我从来没有画任何关注它,但我对10K行的表电流测试表明,MyISAM不甚至使用索引排序的查询,如:

SELECT indexed_field, another_field 
FROM a_table 
ORDER BY indexed_field; 

即使indexed_field是主键。

+0

这并不能解释MySQL为什么不使用那个不太合适的索引,尽管它会使查询速度加快16倍。但是,如果我提供覆盖指数,它确实使用该指数。 – AndreKR

+0

@andrekr,我更新了我的答案。 – newtover