表Retailer_Relations具有以下复合PK索引和建议的索引-
尽管缺少索引可能会有所帮助并且一定可以工作,但我不会在丢失索引上花费太多时间,这些提示是在估计的执行计划上创建的,而不是在实际的执行计划上创建的。
更准确地说,这些索引提示是基于降低计划中的运营商使用Query Bucks™的成本的前提。优化器计算估计的成本,并相应地添加缺失的索引提示。
结果,它们可能是非常错误的。如果不确定是否会有所帮助,最好的办法是前后测试情况。您可以通过SET STATISTICS IO, TIME ON;
在运行查询之前添加语句来做到这一点
。
另外,您可以使用statisticsparser使其更易于阅读这些统计信息。
难道是因为索引中列的顺序?
没错,创建丢失的索引可以提高查询的选择性,例如,查询如下所示:
SELECT RelatedRetailerID
FROM Retailer_Relations
WHERE
RetailerID = 5 AND
RelationType = 20;
或像这样:
SELECT RelatedRetailerID
FROM Retailer_Relations
ORDER BY
RetailerID,
RelationType;
这背后的原因是两个索引都可以在RetailerID上查找,该部分不会改变。但是,如果在RelationType上应用了额外的过滤器/排序,该怎么办?由于它是第三个键值,而不是第二个键值,因此它将在聚集索引中的所有位置。众所周知,这是NCI中的第二个关键值。
好的,但是非聚集索引何时或如何改善查询?
几种情况可能是:
- 如果RelationType过滤了大量值,则剩余I / O可能会很高,从而可能需要非聚集索引(查询#1)
- 在两列上发生排序(一种方式),并且结果集很大(查询2)。
- 正如@AaronBertrand所提到的:如果CI大小与NCI相比有很大差异,则添加NCI将减少受益于它的查询所读取的页面。
NCI旁注
附带说明一下,由于CI关键字列自动包含在所有非聚簇索引中,因此并不完全需要将关键字列添加到NCI的包含列表中。
如果您不确定聚集索引是否保持不变,并且希望始终包含该列,则可以选择这样做。
关于查询本身,如果您通过PasteThePlan添加了执行计划, 我们可以提供更多有关索引/改进查询的信息。
测试中
创建表并添加一些行
CREATE TABLE Retailer_Relations (
RetailerID int ,
RelatedRetailerID int ,
RelationType smallint,
CreatedOn datetime,
CONSTRAINT PK_Retailer_Relations
PRIMARY KEY CLUSTERED (
RetailerID ASC,
RelatedRetailerID ASC,
RelationType ASC
) ON [PRIMARY])
DECLARE @I Int = 1
WHILE @I < 1000
BEGIN
INSERT INTO Retailer_Relations(RetailerID,RelatedRetailerID,RelationType,CreatedOn)
VALUES(@I,@I,@I,GETDATE()
)
set @I += 1
END
查询#1
SELECT RelatedRetailerID
FROM Retailer_Relations
WHERE
RetailerID = 5 AND
RelationType = 20;
没有索引的计划在这里
在搜索时,它正在对RetailerID进行搜索。之后,它会在RelationType上发布剩余I / O谓词
添加索引
CREATE NONCLUSTERED INDEX IX_TEST
ON Retailer_Relations (
RetailerID,
RelationType
)
INCLUDE (
RelatedRetailerID
)
剩余谓词都消失了,所有情况都在两列的搜索谓词中发生。
执行计划
通过第二个查询,添加的索引有用性变得更加明显:
SELECT RelatedRetailerID
FROM Retailer_Relations
ORDER BY
RetailerID,
RelationType;
使用排序运算符在没有索引的情况下进行计划:
使用索引计划,使用索引删除排序运算符