为什么 SQL Server 在 DMV 或查询计划中没有任何缺失的索引请求?

Eri*_*ing 14 performance index sql-server

我有一个 SQL Server 数据库,其中的查询速度很慢,而且有很多锁定和阻塞。

当我查看缺失的索引 DMV 和查询计划时,没有任何建议。

这是为什么?

Eri*_*ing 17

您可能不会丢失索引请求的原因有很多!

我们将更详细地研究其中的一些原因,并讨论该功能的一些一般限制。

一般限制

首先,来自:缺失索引功能的限制

  • 它没有指定在索引中使用的列的顺序。

如本问答中所述:SQL Server 如何确定缺失索引请求中的键列顺序?,索引定义中列的顺序由 Equality vs Inequality 谓词决定,然后是表中的列序数位置。

没有对选择性的猜测,并且可能有更好的顺序可用。弄清楚这一点是你的工作。

特殊索引

缺少索引请求也不包括“特殊”索引,例如:

  • 集群
  • 过滤
  • 分区
  • 压缩的
  • XML-ed
  • 空间化
  • 列存储-d
  • 索引浏览

考虑哪些列?

缺失索引键列是从用于过滤结果的列中生成的,例如:

  • 加入
  • WHERE 子句

Missing Index Included 列是从查询所需的列中生成的,例如:

  • 选择
  • 通过...分组
  • 订购者

尽管很多时候,您排序或分组的列作为关键列是有益的。这可以追溯到限制之一:

  • 它不是为了微调索引配置。

例如,此查询不会注册丢失的索引请求,即使在 LastAccessDate 上添加索引会阻止需要排序(并溢出到磁盘)。

SELECT TOP (1000) u.DisplayName
FROM dbo.Users AS u
ORDER BY u.LastAccessDate DESC;
Run Code Online (Sandbox Code Playgroud)

坚果

也没有对位置进行分组查询。

SELECT TOP (20000) u.Location
FROM dbo.Users AS u
GROUP BY u.Location
Run Code Online (Sandbox Code Playgroud)

坚果

这听起来不是很有帮助!

嗯,是的,但总比没有好。把缺少索引请求想象成一个哭泣的婴儿。你知道有问题,但作为一个成年人,你需要弄清楚这个问题是什么。

你还没有告诉我为什么我没有它们,虽然......

放轻松,巴哥。我们快到了。

跟踪标志

如果启用TF 2330,则不会记录丢失的索引请求。要了解您是否启用了此功能,请运行以下命令:

DBCC TRACESTATUS;
Run Code Online (Sandbox Code Playgroud)

索引重建

重建索引将清除丢失的索引请求。因此,在您开始 Hi-Ho-Silver-Away 重建每个索引之前,一旦有一小部分碎片潜入,请考虑您每次这样做时要清除的信息。

无论如何,您可能还想考虑为什么对索引进行碎片整理没有帮助。除非您使用Columnstore

添加、删除或禁用索引

添加、删除或禁用索引将清除该表的所有缺失索引请求。如果您正在对同一个表进行多次索引更改,请确保在进行任何更改之前将它们全部编写好。

琐碎的计划

如果一个计划足够简单,索引访问选择足够明显,成本足够低,你就会得到一个平凡的计划。

这实际上意味着优化器无需做出基于成本的决策。

通过保罗怀特

哪些类型的查询可以从 Trivial Plan 中受益的细节经常变化,但是诸如连接、子查询和不等式谓词之类的东西通常会阻止这种优化。

当计划不重要时,不会探索额外的优化阶段,也不会请求缺失的索引

查看这些查询与其计划之间的区别:

SELECT *
FROM dbo.Users AS u
WHERE u.Reputation = 2;

SELECT *
FROM dbo.Users AS u
WHERE u.Reputation = 2
AND 1 = (SELECT 1);
Run Code Online (Sandbox Code Playgroud)

坚果

第一个计划是微不足道的,没有显示任何请求。可能存在错误阻止丢失索引出现在查询计划中的情况;不过,它们通常更可靠地记录在缺失的索引 DMV 中。

SARG能力

即使使用索引,优化器也无法有效使用索引的谓词可能会阻止它们被记录。

通常不可 SARGable 的事情是:

  • 包含在函数中的列
  • 列 + SomeValue = SomePredicate
  • 列 + 另一列 = SomePredicate
  • 列 = @Variable OR @Variable IS NULL

例子:

SELECT *
FROM dbo.Users AS u
WHERE ISNULL(u.Age, 1000) > 1000;


SELECT *
FROM dbo.Users AS u
WHERE DATEDIFF(DAY, u.CreationDate, u.LastAccessDate) > 5000


SELECT *
FROM dbo.Users AS u
WHERE u.UpVotes + u.DownVotes > 10000000


DECLARE @ThisWillHappenWithStoredProcedureParametersToo NVARCHAR(40) = N'Eggs McLaren'
SELECT *
FROM dbo.Users AS u
WHERE u.DisplayName LIKE @ThisWillHappenWithStoredProcedureParametersToo 
      OR @ThisWillHappenWithStoredProcedureParametersToo IS NULL;
Run Code Online (Sandbox Code Playgroud)

这些查询都不会注册丢失的索引请求。有关这些的更多信息,请查看以下链接:

你已经有了一个好的索引

拿这个指数:

CREATE INDEX ix_whatever ON dbo.Posts(CreationDate, Score) INCLUDE(OwnerUserId);

这个查询看起来没问题:

SELECT p.OwnerUserId, p.Score
FROM dbo.Posts AS p
WHERE p.CreationDate >= '20070101'
AND   p.CreationDate < '20181231'
AND   p.Score >= 25000
AND 1 = (SELECT 1)
ORDER BY p.Score DESC;
Run Code Online (Sandbox Code Playgroud)

该计划是一个简单的寻求...

坚果

但是因为前导键列用于选择较少的谓词,我们最终做了比我们应该做的更多的工作:

表“帖子”。扫描计数 13,逻辑读取 136890

如果我们改变索引键列顺序,我们做的工作就会少很多:

CREATE INDEX ix_whatever ON dbo.Posts(Score, CreationDate) INCLUDE(OwnerUserId);

坚果

阅读量明显减少:

表“帖子”。扫描计数 1,逻辑读取 5

SQL Server 正在为您创建索引

在某些情况下,SQL Server 将选择通过索引假脱机动态创建索引。当存在索引假脱机时,不会出现丢失的索引请求。当然,自己添加索引可能是个好主意,但不要指望 SQL Server 帮助您解决这个问题。

坚果


归档时间:

查看次数:

1391 次

最近记录:

6 年,2 月 前