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()
、LIKE
或 IS [NOT] NULL
)。
所以你的列k1
受益于索引,然后第二列真的不能从索引中受益。您可以在 EXPLAIN 的 key_len
字段中看到此效果。它只会使用索引的一部分,对应k1
数据类型的大小,而不是k1
和k2
。
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 中的索引,用于按 DESC、BETWEEN 和几个可能的字段集进行查询