Sql server 如何对多键索引进行简单的范围扫描?
在此处使用Microsoft SQL Server。 给定此设置(两列上的聚集索引): 如何获得n1=5,n2=6之后的值(按n1,n2排序时)?我有以下的尝试Sql server 如何对多键索引进行简单的范围扫描?,sql-server,tsql,Sql Server,Tsql,在此处使用Microsoft SQL Server。 给定此设置(两列上的聚集索引): 如何获得n1=5,n2=6之后的值(按n1,n2排序时)?我有以下的尝试 declare @n1boundary int = 5; declare @n2boundary int = 6; SELECT N1, N2 FROM mytemp WHERE N1 = @n1boundary AND N2 > @n2boundary OR N1 > @n1boundary ORDER BY N1, N
declare @n1boundary int = 5;
declare @n2boundary int = 6;
SELECT N1, N2
FROM mytemp
WHERE N1 = @n1boundary AND N2 > @n2boundary
OR N1 > @n1boundary
ORDER BY N1, N2
它给出了我想要的结果,但是语法看起来很笨拙,它执行了两次扫描。在我看来,从理论上讲,用一次扫描就可以做到这一点
[编辑]我正在查看的扫描是在“设置统计信息IO”设置为“开”时报告的扫描:
Table 'mytemp'. Scan count 2, logical reads 4
我在我的系统上尝试了一次搜索操作 Microsoft SQL Server 2008(SP1)- 10.0.2531.0(X64)2009年3月29日10:11:52版权所有(c)1988-2008 微软公司标准 Windows NT 5.2上的版本(64位) (构建3790:Service Pack 2) (虚拟机)
当我运行这个程序时,我得到了一个相当好的执行计划,只需执行聚集索引搜索 另一个选项如下所示,使用复合键,但这会进行聚集索引扫描,因此在大型表上性能可能不太好
declare @n1boundary int = 5;
declare @n2boundary int = 6;
select N1, N2
from mytemp
where cast(N1 as varchar(2))+cast((N2-1) as varchar(2)) >
cast(cast(@n1boundary as varchar(2))+cast((@n2boundary-1) as varchar(2)) as int)
根据PCurd的回答,这里有另一个奇怪的解决方法。它保持聚集索引的串联,为其编制索引,然后对其执行简单的范围扫描:
ALTER TABLE mytemp
ADD stringify as
right('00' + cast(n1 as varchar), 2) +
right('00' + cast(n2 as varchar), 2) PERSISTED;
CREATE NONCLUSTERED INDEX ix_mytemp
ON mytemp(stringify)
INCLUDE (n1, n2)
declare @n1boundary int = 5;
declare @n2boundary int = 6;
SELECT n1, n2
FROM mytemp
WHERE stringify >
right('00' + cast(@n1boundary as varchar), 2) +
right('00' + cast(@n2boundary as varchar), 2)
ORDER BY stringify;
这是草率的,也不是我想要的。你确定你没有因为或部分而遗漏几个括号吗?缺少括号是个意外。事实证明,优先级是预期的(whew)。对于没有参数的查询,我得到了相同的结果:其中N1=@n1boundary和N2>@n2boundary或N1>@n1boundary应该更清楚。它看起来像查询计划中的单个搜索。但是SET STATISTICS IO输出中的扫描和读取次数增加了一倍(这也是我现在看到的)。扫描计数1,逻辑读取2扫描计数如下:表“mytemp”。扫描计数1,逻辑读取2,物理读取0,预读读取0,lob逻辑读取0,lob物理读取0,lob预读读取0。是的,这是一个简单的完全扫描。我在找范围扫描。但是串联的想法很有趣
ALTER TABLE mytemp
ADD stringify as
right('00' + cast(n1 as varchar), 2) +
right('00' + cast(n2 as varchar), 2) PERSISTED;
CREATE NONCLUSTERED INDEX ix_mytemp
ON mytemp(stringify)
INCLUDE (n1, n2)
declare @n1boundary int = 5;
declare @n2boundary int = 6;
SELECT n1, n2
FROM mytemp
WHERE stringify >
right('00' + cast(@n1boundary as varchar), 2) +
right('00' + cast(@n2boundary as varchar), 2)
ORDER BY stringify;