让我们将一百万行和几列放入一个临时表中:
CREATE TABLE #174860 (
PK INT NOT NULL,
COL1 INT NOT NULL,
COL2 INT NOT NULL,
PRIMARY KEY (PK)
);
INSERT INTO #174860 WITH (TABLOCK)
SELECT RN
, RN % 1000
, RN % 10000
FROM
(
SELECT TOP 1000000 ROW_NUMBER () OVER (ORDER BY (SELECT NULL)) RN
FROM master..spt_values v1,
master..spt_values v2
) t;
CREATE INDEX IX_174860_IX ON #174860 (COL1) INCLUDE (COL2);
在这里,我在PK
列上有一个聚集索引(默认情况下)。有一个非聚集索引COL1
,其键列为,COL1
包括COL2
。
考虑以下查询:
SELECT *
FROM #174860
WHERE PK >= 15000 AND PK < 15005
AND COL2 = 5000;
在这里我没有用,BETWEEN
因为亚伦·贝特朗一直在围绕这个问题。
SQL Server优化器应如何查询?好吧,我知道启用筛选器PK
会将结果集减少到五行。SQL Server可以使用聚簇索引跳到那五行,而不用读取表中的所有百万行。但是,聚集索引仅将PK列作为键列。将行读入内存后,我们需要在上应用过滤器COL2
。在这里,PK
是一个搜索谓词,COL2
也是一个谓词。
SQL Server使用查找谓词查找五行,并使用常规谓词将这五行进一步减少为一行。
如果我以不同的方式定义聚簇索引:
CREATE TABLE #174860 (
PK INT NOT NULL,
COL1 INT NOT NULL,
COL2 INT NOT NULL,
PRIMARY KEY (COL2, PK)
);
并运行相同的查询,我得到不同的结果:
在这种情况下,SQL Server可以在WHERE
子句中使用这两个列。使用键列从表中仅读取一行。
再看一个示例,请考虑以下查询:
SELECT *
FROM #174860
WHERE COL1 = 500
AND COL2 = 3545;
IX_174860_IX索引是覆盖索引,因为它包含查询所需的所有列。但是,只有COL1
一个键列。SQL Server可以在该列中查找以找到具有匹配COL1
值的1000行。它可以进一步过滤列中的那些行,COL2
以将最终结果集减少为0行。