MySQL:为具有多个BETWEEN表达式的WHERE子句建立索引

时间:2013-06-30 07:46:07

标签: mysql optimization indexing between

在如下的表格上:

CREATE TABLE foo (..., k1 INTEGER, k2 INTEGER)

我想索引一个查询,例如:

SELECT * FROM foo WHERE (k1 BETWEEN @a AND @b) AND (k2 BETWEEN @x AND @y)

在我看来,在(k1,k2)上创建BTREE索引应该可以解决问题,但是EXPLAIN说不然。它说它将使用4的key_len来匹配k1,但是当匹配k2时它并没有真正受益(除了在表格中缩小了一些东西。但是如果k1的范围很宽,那么仍然有很多做约束k2的工作。)

一篇MySQL性能博客文章可能表明不应该这样做,因为一旦使用了间隔范围,它就会扫描剩下的部分:http://www.mysqlperformanceblog.com/2009/09/12/3-ways-mysql-uses-indexes/

是否有其他索引方案或多表方案可以使此查询达到最佳效果?

我想使用分区,我将在k1上进行分区。文档说优化器会考虑到这一点。如果我创建了许多分区,并且数据是公平分布的,那么如果引擎只需要访问少量分区,则线性扫描会更好。但是,A)我的特定mysql服务器上没有启用分区,我无权更改它,B)我实际应用程序中实际上有3个BETWEEN语句。因此,分区只会帮助第一个BETWEEN表达式仍有两个。

这似乎是一种相当常见的情况,可能会出现并需要编制索引,但我没有太多看到这方面的问题。

提前感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

确实,使用标准B树搜索,您可以搜索范围谓词中的一个列(BETWEEN计为范围谓词,<也是如此, >!=IN()LIKEIS [NOT] NULL)。

因此,您的列k1会从索引中受益,然后第二列确实无法从索引中受益。您可以在EXPLAIN的key_len字段中看到此效果。它只会使用与k1数据类型的大小相对应的索引的一部分,而不是k1k2

MySQL 5.6使用名为索引条件下推的新功能改进了优化器。这意味着在索引缩小了给定k1的搜索后,剩余的搜索项将传递到存储引擎,因此至少不是 all 这些行需要由SQL引擎扫描。存储引擎可以对它们进行预过滤。

有关MySQL 5.6中ICP的更多详细信息,请参阅https://dev.mysql.com/doc/refman/5.6/en/index-condition-pushdown-optimization.html

另见我的演讲How to Design Indexes, Really