查询发生了一件奇怪的事情。我有一个包含两个bigints的表StartNum和EndNum,用于定义数字范围。我在这两列上都有一个索引。该查询采用给定的数字,并返回其所属的范围。 WHERE子句是where @Num >= StartNum and @Num <= EndNum
。
在探查器中,搜索列表开头附近的数字和结尾附近的数字之间存在很大差异。该数字在列表中越靠后,则需要的读取次数和持续时间就越多。查询计划表明它正在对我的索引使用搜索。
因为索引是一棵平衡的树,所以肯定不会有太大的差异。有人可以向我解释一下吗?
小字:
这是在SQL 2005 Workgoup版本上。表中大约有200,000行。索引是非聚簇的(聚簇索引在标识列上,但是数据以StartNum顺序插入)。索引有716页,深度为3,碎片为3%。
最佳答案
这取决于您的查询。如果仅查询这两个值,例如:
SELECT StartNum, EndNum
FROM Books
WHERE (@Num >= StartNum) AND (@Num <= EndNum)
在这种情况下,SQL Server只需搜索两个索引即可返回数字。您的两个索引包含您被索引的值,并且因为这是一个索引,所以它们被排序了。
但我确定您实际上在查询中包括其他列:
SELECT BookID, Title, IDBN, Author, StartNum, EndNum
FROM Books
WHERE (@Num >= StartNum) AND (@Num <= EndNum)
在这种情况下,SQL Server一旦找到与条件匹配的行的ID,就必须返回数据库并找到这些行,以便它可以为您返回:
标题
书号
作者
除了已经从两个索引中获得的值之外:
StartNum
EndNum
书号
注意:StartNum上的索引隐式包含聚集键的值,因为这是它知道与索引中的条目相对应的行的方式。
问题是,如果必须在表中查找“太多书”,那么从上到下阅读整个表可能会更快。
打个比方:您可以在书的索引中查找对“设计模式”的所有引用。
设计模式:4、89、221、442
如果只有4个条目,则可以倒向索引中列出的页面。这称为书签查找。
但是,如果索引显示有827个短语引用该怎么办?
计算机:1、2、6 [剪切825个条目],1087、1128
然后,通读本书以自行找到它们可能会更快。在这种情况下,我们放弃并扫描整本书。如果表具有聚集索引,则SQL Server将此称为聚集索引扫描,如果没有聚集索引,则称为表扫描(即,这是“堆表”)
如果您只是在查询中引用StartNum和EndNum(假设您正在计数),那么我敢肯定,您将始终看到较低的读取次数和执行时间。但是,如果您包括其他列,并且SQL Server认为该查询将返回太多行(例如,超过表的5%),那么它将忘记索引并扫描整个表表。
有一个交叉点,SQL Server知道表中StartNum和EndNum值的分布,因为它会采样值并对它们的分布进行统计。如果@Num的某些值恰好返回几行,并且SQL Server知道这一点,它将执行相对较少的书签查找。但是,如果您的数据分发将导致更多行返回,那么您将获得聚集索引扫描。
关于sql-server - SQL索引查找,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/956346/