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

Posted

技术标签:

【中文标题】MySQL:索引具有多个 BETWEEN 表达式的 WHERE 子句【英文标题】:MySQL: Indexing for a WHERE clause with multiple BETWEEN expressions 【发布时间】:2013-06-30 07:46:07 【问题描述】:

在桌子上,例如:

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 表达式,还有两个。

这似乎是一种相当常见的情况,需要编制索引,但我很少看到以这种方式提出的问题。

提前感谢您的帮助!

【问题讨论】:

MySQL 并不是真正以其查询优化而闻名。 我知道。这就是我试图优化它的原因。 :) 优化器可以选择使用索引或进行全面扫描,如果它认为扫描会更快。它是根据统计数据完成的。如果您可以向我们提供EXPLAIN 的输出并使用INDEX 提示来使用您的 (k1,k2) 索引。 【参考方案1】:

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

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

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

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

另请参阅我的演示文稿How to Design Indexes, Really。

【讨论】:

以上是关于MySQL:索引具有多个 BETWEEN 表达式的 WHERE 子句的主要内容,如果未能解决你的问题,请参考以下文章

mysql join不使用'between'运算符的索引

浅析索引

MySQL BETWEEN 查询不使用索引

MySQL 中的索引,用于按 DESC、BETWEEN 和几个可能的字段集进行查询

MySQL处理重复键错误插入具有多个唯一索引的表;不是多列唯一索引

具有多个共享列的 MySql 索引策略