我有一个SQL Server数据库,查询速度很慢,并且有很多锁定和阻塞。
当我查看缺少的索引DMV和查询计划时,没有任何建议。
这是为什么?
我有一个SQL Server数据库,查询速度很慢,并且有很多锁定和阻塞。
当我查看缺少的索引DMV和查询计划时,没有任何建议。
这是为什么?
Answers:
我们将更详细地探讨一些原因,并讨论该功能的一些一般限制。
首先,来自:缺少索引功能的局限性:
- 它没有指定在索引中使用列的顺序。
如本问答中所述:SQL Server如何确定丢失索引请求中的键列顺序?,索引定义中的列顺序由等式vs不等式谓词决定,然后由表中的列序位置决定。
没有关于选择性的猜测,可能会有更好的选择。解决这个问题是您的工作。
特殊索引
缺少索引的请求也不会包含“特殊”索引,例如:
缺少索引键列是从用于过滤结果的列中生成的,例如:
缺少索引包含的列是从查询所需的列中生成的,例如:
即使经常使用,按顺序排序或分组的列也可以作为关键列。这可以回溯到以下限制之一:
- 它并非旨在微调索引配置。
例如,即使在LastAccessDate上添加索引将防止需要排序(并溢出到磁盘),该查询也不会注册丢失的索引请求。
SELECT TOP (1000) u.DisplayName
FROM dbo.Users AS u
ORDER BY u.LastAccessDate DESC;
该分组也不在位置上查询。
SELECT TOP (20000) u.Location
FROM dbo.Users AS u
GROUP BY u.Location
是的,但是总比没有好。想想缺少索引的请求就像哭泣的婴儿。您知道有问题,但是由成年人来确定问题所在。
放松,巴克。我们到了那里。
如果启用TF 2330,则不会记录缺少的索引请求。要了解是否启用了此功能,请运行以下命令:
DBCC TRACESTATUS;
重建索引将清除丢失的索引请求。因此,在使用Hi-Ho-Silver-Away重新构建每个索引时,都会遇到碎片碎片的情况,请考虑一下每次执行此操作时要清除的信息。
您可能还想考虑为什么对索引进行碎片整理无济于事。除非您使用Columnstore。
添加,删除或禁用索引将清除该表的所有缺失索引请求。如果要在同一张表上进行多个索引更改,请确保在进行任何更改之前先全部编写脚本。
如果一个计划足够简单,并且索引访问选择足够明显,并且成本足够低,那么您将获得一个简单的计划。
这实际上意味着优化器没有基于成本的决策。
通过保罗·怀特(Paul White):
可以从琐碎计划中受益的查询类型的详细信息经常更改,但是联接,子查询和不等式谓词通常会阻止此优化。
当计划琐碎时,不会探索其他优化阶段,也不会要求缺少索引。
查看这些查询与其计划之间的区别:
SELECT *
FROM dbo.Users AS u
WHERE u.Reputation = 2;
SELECT *
FROM dbo.Users AS u
WHERE u.Reputation = 2
AND 1 = (SELECT 1);
第一个计划是微不足道的,没有显示请求。在某些情况下,错误会阻止缺失的索引出现在查询计划中。但是,通常可以更可靠地将它们记录在丢失的索引DMV中。
优化器即使使用索引也无法有效使用索引的谓词可能会阻止它们被记录。
通常无法保存的内容包括:
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;
这些查询都不会注册丢失的索引请求。有关这些的更多信息,请查看以下链接:
取这个索引:
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;
该计划是一个简单的寻求...
但是,由于前导关键字列是针对选择性较低的谓词的,因此我们最终要做的工作比我们应该做的要多:
表“帖子”。扫描计数13,逻辑读取136890
如果我们更改索引键列的顺序,我们将减少很多工作:
CREATE INDEX ix_whatever ON dbo.Posts(Score, CreationDate) INCLUDE(OwnerUserId);
而且读取次数明显减少:
表“帖子”。扫描计数1,逻辑读取5
在某些情况下,SQL Server将选择通过索引假脱机动态创建索引。存在索引假脱机时,不会缺少索引请求。当然,自己添加索引可能是个好主意,但不要指望SQL Server可以帮助您解决这一问题。