为只有一个匹配的Between查询索引SQL?

Posted

技术标签:

【中文标题】为只有一个匹配的Between查询索引SQL?【英文标题】:Indexing SQL for Between query with only one match? 【发布时间】:2012-10-18 15:05:17 【问题描述】:

我们有一个包含超过 200 万行的表,针对它的所有查询都将是使用 Column1Column2 的 Between 查找。此外,只有一种可能的结果。比如……

Col1     Col2
1        5
6        10
11       15

select * from table1 where 8 between Col1 and Col2

我目前在 Col1Col2 上有一个唯一的聚集索引。到目前为止,我一直无法弄清楚如何进一步调整查询和索引以最小化处理的行。执行计划目前报告在找到唯一正确答案时处理的成本接近 0.5 和 113k 行。

我可能会忽略哪些选项?

根据要求,来自当前执行计划的一些细节:

Operation
 Clustered Index Seek
Predicate
 CONVERT_IMPLICIT(bigint,[@2],0)<=[Col2]
Seek Predicate
 Seek Keys[1]: End: Col1 <= Scalar Operator(CONVERT_IMPLICIT(bigint,[@1],0))

【问题讨论】:

写成'select * from table1 where Col1==8'会有帮助吗 Col1 中的步长是否始终为 5?如果是这样,那么答案很简单:) 你的执行计划是什么样的?您能否将其添加到问题中? Column1和Column2的数据类型是什么?以及如何将 8 的值放入查询中(参数、硬编码等)? 嗯,与您发布的 SQL 查询示例相比,您发布的“当前执行计划”看起来非常不同(并且错误)。能否请您发布您的实际 SQL 代码,因为这里不正确。 【参考方案1】:

范围是否总是不重叠的?你提到总是只有一场比赛。如果是,你可以写成:

SELECT * FROM table1 
   WHERE 8 <= Col2 
   ORDER BY Col2 ASC
   LIMIT 1

这将为您提供Col2 的最低值高于 8 的行 - 这是您感兴趣的范围。该索引仅在 Col2 上需要,并且成本应该很小。

由于您没有提及您使用的 DBMS,LIMIT 1 应替换为您的 DB 用于获取前 N 个结果的任何内容。

您必须检查代码中的Col1 &lt;= your_value,以确保您要查找的值确实在该范围内。

【讨论】:

【参考方案2】:

我想我已经找到了答案。我必须首先在 Col1 上创建唯一聚集索引,然后在 Col2 上创建唯一非聚集索引。然后必须更新查询以强制对每个索引进行查找。

select * from table1 where Col1 = 
    (select max(Col1) from table1 where Col1 <= 8)
and Col2 = 
    (select min(Col2) from table1 where Col2 >= 8)

执行计划现在报告 0.0098 成本和 1 行已处理。

【讨论】:

【参考方案3】:
select * from table1 where Col1 <= 8 and Col2 >= 8

也许两列的“中间”会导致问题。

此外,两列 (Col1, Col2) 上应该只有 1 个复合索引。

【讨论】:

以上是关于为只有一个匹配的Between查询索引SQL?的主要内容,如果未能解决你的问题,请参考以下文章

使用 between 语句查询包含数字的 SQL 列 varchar6

联合索引最左匹配原则

SQL Server 查询使用 BETWEEN 过滤器带来不匹配的数据

SQL Server 索引如何帮助将 BETWEEN 用于给定查询

sql优化

mysql性能调优注意事项