SQL Server如何确定丢失索引请求中的键列顺序?


Answers:


44

当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

所有三个表具有完全相同的数据,并且查询是相同的。唯一的区别是字段顺序-这也是我们缺少索引请求的区别:

具有3个相等字段的执行计划

在执行计划中,缺少索引请求中的列顺序与表中的列顺序完全匹配。例如,在dbo.NumberLetterDate中,数字列是第一列,因此在缺少索引的请求中它也是第一列:

  • 在dbo.NumberLetterDate上,缺少的索引在fINT(数字),fLetter(nvarchar),fDate上,与表中字段的顺序相同
  • 在dbo.LetterDateNumber上,索引顺序切换为fNVARCHAR,fDATE,fINT
  • 在dbo.DateNumberLetter上,索引顺序切换为fDATE,fINT,fNVARCHAR

对于像这样的单表操作,索引字段的顺序似乎并不取决于选择性,数据类型或查询中的位置。(我将其留给其他人以通过更复杂的查询和联接来证明这一点。)

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个丢失的索引请求中最后出现,因为这是一个不平等搜索:

具有2个相等和1个不相等搜索的执行计划

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

由于没有相等搜索,所有三个字段在缺失索引建议中都具有相同的优先级顺序,现在我们回到纯粹按字段顺序排序:

具有3个不平等搜索的执行计划

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.