2012-02-08 69 views
2

的问题MySQL的使用上大表不正确的索引

我有一个表,这是大约200万行(115 MB),它是关于要大得多。当在桌面上运行一些实用程序脚本时,我发现我的一个查询需要很长时间(15+秒),而几乎相同的查询在之前不到半秒。下面是查询:

查询1:

SELECT `id` FROM `my_table` WHERE `my_column`='test' ORDER BY `id` LIMIT 28000, 1000 
Execution time: 0.204 seconds 

查询2:

SELECT `id` FROM `my_table` WHERE `my_column`='test' ORDER BY `id` LIMIT 29000, 1000 
Execution time: 10.203 seconds 


索引和表信息

id是一个主键,my_column也索引(虽然目前它的基数我只有S1)

• ID是一个i​​nt
• my_column是一个varchar(50)

查询解释

查询1:类型:索引,possible_keys :my_column,key:PRIMARY,key_len:4,:29000,额外:使用其中

问题2:类型:范围,possible_keys:my_column,:my_column,key_len:行 :2,139,123 额外:使用where;使用filesort

正如你可以看到第二个查询使用my_column键和文件并永久使用,但我所做的只是将极限偏移量增加1,000。

如何暂时解决了这一问题

1)如果我删除WHERE my_column = 'test'条件MySQL优化正确使用主键进行排序,但我不能删除这个条件,因为很快会有其他在my_column中我需要为这个查询过滤掉这些值。 2)如果我使用FORCE INDEX (PRIMARY),mysql优化器也会使用正确的索引,但这似乎是一种破解。

我的问题

究竟为什么mysql的选择使用my_column指数,而不是主键的?有没有更好的方法来处理这个在表定义,索引或我的查询结构?

回答

3

我会尝试在(my_column, id)的组合上创建一个composite index

+0

叹息......我只是喜欢愚蠢的疏忽。感谢您的帮助 – Jeff 2012-02-08 21:53:46

0

这很奇怪。你有没有尝试添加一个复合索引?

ALTER TABLE `my_table` ADD INDEX (id, my_column); 

如果您只是选择id并且始终只使用where子句中的my_column,那么这应该很好。

+0

您希望'my_column'成为组合索引的最左列,因为它是在WHERE子句中测试的那个列。 – 2012-02-08 21:54:55

0

随着您目前的设置,有两种明显的方式来执行查询。

  1. 检索id订单中的行并丢弃与WHERE子句不匹配的行。
  2. 检索与WHERE子句匹配的行,并按照id的顺序对它们进行排序。

推测MySQL猜测根据你想要的行数来决定使用哪种方式。

但是,如果你创建两个my_columnid索引,MySQL能够然后retrive行中my_column, id顺序,开始于第一行,其中my_column = 'test'

请注意,在一般情况下,这要求WHERE子句中的所有条件均相等,并且WHERE子句中的所有列都存在于索引中。