如何在多键索引上进行简单的范围扫描?

时间:2011-04-04 15:44:08

标签: sql-server tsql

在此处使用Microsoft SQL Server。 鉴于此设置(两列上的聚簇索引):

use tempdb;
CREATE TABLE mytemp
(
    N1 INT NOT NULL,
    N2 INT NOT NULL,
    PRIMARY KEY (N1, N2)
);

INSERT mytemp (N1, N2)
SELECT N1.number, N2.number
FROM (VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10)) AS N1(number)
CROSS JOIN (VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10)) AS N2(number)

如何在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, N2

它给了我想要的结果,但语法看起来很笨拙,它执行两次扫描。在我看来,从理论上讲,应该可以通过一次扫描来完成这项工作。

[编辑]我正在查看的扫描是在SET STATISTICS IO设置为ON的情况下报告的:

Table 'mytemp'. Scan count 2, logical reads 4

3 个答案:

答案 0 :(得分:0)

当我在我的系统上尝试时,我进行了一次搜索操作。

  

Microsoft SQL Server 2008(SP1) -   10.0.2531.0(X64)2009年3月29日10:11:52版权所有(c)1988-2008   微软公司标准   Windows NT 5.2上的版本(64位)    (Build 3790:Service Pack 2)   (VM)

enter image description here

答案 1 :(得分:0)

当我运行这个时,我得到了一个相当不错的执行计划,仅执行聚簇索引查找。

另一个选项如下所示,使用复合键,但这会产生聚簇索引SCAN,因此在大型表上性能可能不太好

    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)

答案 2 :(得分:0)

根据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;

它很草率,也不是我想要的。