SQL Server如何确定其对查询计划的缺失索引建议中的关键列的顺序?
SQL Server如何确定其对查询计划的缺失索引建议中的关键列的顺序?
Answers:
当SQL Server为特定查询计划创建缺少索引建议时,它将可能的键列分为2组。第一组包含所有推荐的列,它们是EQUALITY谓词的一部分。第二组包含作为INEQUALITY谓词一部分的所有推荐列。
在每个集合中,根据表定义,按列的顺序位置对列进行排序。
(非常感谢Brent Ozar为Stack Overflow数据库构建了一个repro脚本来证明了这一点!)
1.创建3个相同的表,但将它们的列以不同的顺序放置。(这里的原因是使用各种列名和数据类型来表明这不会影响缺少索引建议中的列顺序。)
CREATE TABLE dbo.NumberLetterDate (ID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
fINT INT, fNVARCHAR NVARCHAR(40), fDATE DATETIME, AboutMe NVARCHAR(MAX));
GO
CREATE TABLE dbo.LetterDateNumber (ID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
fNVARCHAR NVARCHAR(40), fDATE DATETIME, fINT INT, AboutMe NVARCHAR(MAX));
GO
CREATE TABLE dbo.DateNumberLetter (ID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
fDATE DATETIME, fINT INT, fNVARCHAR NVARCHAR(40), AboutMe NVARCHAR(MAX));
GO
2.用相同的数据填充表。通过真实数据分布,从“用户”表中获取100,000行。
INSERT INTO dbo.NumberLetterDate(fINT, fNVARCHAR, fDATE, AboutMe)
SELECT TOP 100000 Age, DisplayName, LastAccessDate, AboutMe
FROM dbo.Users WITH (NOLOCK)
ORDER BY Id;
GO
INSERT INTO dbo.LetterDateNumber(fINT, fNVARCHAR, fDATE, AboutMe)
SELECT TOP 100000 Age, DisplayName, LastAccessDate, AboutMe
FROM dbo.Users WITH (NOLOCK)
ORDER BY Id;
GO
INSERT INTO dbo.DateNumberLetter(fINT, fNVARCHAR, fDATE, AboutMe)
SELECT TOP 100000 Age, DisplayName, LastAccessDate, AboutMe
FROM dbo.Users WITH (NOLOCK)
ORDER BY Id;
GO
3.编写需要索引的查询。从3个相等过滤器开始,在所有3个字段中过滤一个精确值。请注意,所有3个查询都以相同的顺序具有相同的字段:
SELECT ID
FROM dbo.NumberLetterDate
WHERE fINT = 100
AND fNVARCHAR = 'Brent Ozar'
AND fDATE = '2018/01/01'
AND 1 = (SELECT 1);
SELECT ID
FROM dbo.LetterDateNumber
WHERE fINT = 100
AND fNVARCHAR = 'Brent Ozar'
AND fDATE = '2018/01/01'
AND 1 = (SELECT 1);
SELECT ID
FROM dbo.DateNumberLetter
WHERE fINT = 100
AND fNVARCHAR = 'Brent Ozar'
AND fDATE = '2018/01/01'
AND 1 = (SELECT 1);
GO
所有三个表具有完全相同的数据,并且查询是相同的。唯一的区别是字段顺序-这也是我们缺少索引请求的区别:
在执行计划中,缺少索引请求中的列顺序与表中的列顺序完全匹配。例如,在dbo.NumberLetterDate中,数字列是第一列,因此在缺少索引的请求中它也是第一列:
对于像这样的单表操作,索引字段的顺序似乎并不取决于选择性,数据类型或查询中的位置。(我将其留给其他人以通过更复杂的查询和联接来证明这一点。)
4.混入不等式过滤器。例如,在INT字段上,输入<> 100作为过滤器:
SELECT ID
FROM dbo.NumberLetterDate
WHERE fINT <> 100
AND fNVARCHAR = 'Brent Ozar'
AND fDATE = '2018/01/01'
AND 1 = (SELECT 1);
SELECT ID
FROM dbo.LetterDateNumber
WHERE fINT <> 100
AND fNVARCHAR = 'Brent Ozar'
AND fDATE = '2018/01/01'
AND 1 = (SELECT 1);
SELECT ID
FROM dbo.DateNumberLetter
WHERE fINT <> 100
AND fNVARCHAR = 'Brent Ozar'
AND fDATE = '2018/01/01'
AND 1 = (SELECT 1);
GO
在执行计划中,相等字段排在第一位,然后是不平等字段-在这里,fINT在所有3个丢失的索引请求中最后出现,因为这是一个不平等搜索:
5.使用3个不等式过滤器。对所有字段(<>)使用相同的搜索:
SELECT ID
FROM dbo.NumberLetterDate
WHERE fINT <> 100
AND fNVARCHAR <> 'Brent Ozar'
AND fDATE <> '2018/01/01'
AND 1 = (SELECT 1);
SELECT ID
FROM dbo.LetterDateNumber
WHERE fINT <> 100
AND fNVARCHAR <> 'Brent Ozar'
AND fDATE <> '2018/01/01'
AND 1 = (SELECT 1);
SELECT ID
FROM dbo.DateNumberLetter
WHERE fINT <> 100
AND fNVARCHAR <> 'Brent Ozar'
AND fDATE <> '2018/01/01'
AND 1 = (SELECT 1);
GO
由于没有相等搜索,所有三个字段在缺失索引建议中都具有相同的优先级顺序,现在我们回到纯粹按字段顺序排序: