诊断“有时”缓慢查询的建议


20

我有一个存储过程,该过程通过覆盖索引从索引视图返回结果。通常,它运行速度很快(〜10毫秒),有时甚至可以运行8秒钟。

这是一个随机执行的示例(注意:这不是一个缓慢的执行,但是查询文本与传递的值相同):

declare @p2 dbo.IdentityType
insert into @p2 values(5710955)
insert into @p2 values(5710896)
insert into @p2 values(5710678)
insert into @p2 values(5710871)
insert into @p2 values(5711103)
insert into @p2 values(6215197)
insert into @p2 values(5710780)

exec ListingSearch_ByLocationAndStatus @statusType=1,@locationIds=@p2

这是SPROC:

ALTER PROCEDURE [dbo].[ListingSearch_ByLocationAndStatus]
    @LocationIds IdentityType READONLY,
    @StatusType TINYINT
AS
BEGIN
    SET NOCOUNT ON;

    SELECT      -- lots of fields
    FROM        [dbo].[ListingSearchView][a] WITH (NOEXPAND)
    INNER JOIN  @LocationIds [b] ON [a].[LocationId] = [b].[Id]
    WHERE       [a].[StatusType] = @statusType
    OPTION (RECOMPILE);

(注意:我OPTION (RECOMPILE)最近在提出一些建议后添加了提示,但并没有帮助。

这是覆盖索引(请注意:该视图在上还有一个聚集索引ListingId,这是唯一的)

CREATE NONCLUSTERED INDEX [IX_ListingSearchView_ForAPI] ON [dbo].[ListingSearchView]
(
    [LocationId] ASC,
    [StatusType] ASC
)
INCLUDE ( -- all the fields in the query) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
GO

我使用showplan XML统计信息进行了探查器跟踪。

这是一个慢速的(6秒),以及相关的计划: 在此处输入图片说明

看起来完全符合我的预期,并且在查询快速时是相同的计划。

如果有帮助,请放大以下计划中昂贵的部分: 在此处输入图片说明

如果有帮助,以下是视图/支持表的完整架构:https : //pastebin.com/wh1sRcbQ

笔记:

  • 索引已进行碎片整理,统计数据是最新的。
  • 最初,查询是针对视图进行内联的,但是我搬到了SPROC来尝试并帮助稳定。没有帮助。
  • 添加WITH OPTION (RECOMPILE);提示(行不通,所以不能进行参数嗅探吗?)
  • 系统中的其他查询有时也会运行缓慢,并且在计划中也没有明显的问题。
  • 可以锁定吗?不确定如何确认。

关于下一步我可以尝试的任何想法?

谢谢


1
评论不作进一步讨论;此对话已转移至聊天大家:请使用该工具进一步讨论此问题。
保罗·怀特说GoFundMonica

给定的链接不起作用。proc查询很简单,实际和估计的行数之间存在很大的差异,这是值得关注的问题。我认为问题出在视图查询中。我认为数据不足。应该关闭
KumarHarsh

查询运行时,您是否尝试过运行WhoIsActive(由Adam Machanic设计)?whoisactive.com它包含有关等待任务的信息,应该为您指明正确的方向。
MJH

您是否消除了导致该问题的数据库外部问题。也许还有其他一些应用程序导致同步IO与数据库共享存储?
约翰

Answers:


2

我真的不认为使用OPTION (RECOMPILE)可以消除参数嗅探的有效方法。

当SQL对特定查询感到困惑并且由于看到新参数而认为它是新查询时,就会发生参数嗅探。这很慢,因为要花费额外的时间来生成新的执行计划。

该选项所做的只是迫​​使SQL每次都生成一个新计划,几乎是同一回事。相反,您可能要考虑使用此提示添加默认参数:

OPTION(OPTIMIZE FOR(@LocationIds='xx',@StatusType='xx'))

选择默认参数时,请确保使用统计上具有代表性的集。
这将迫使每次都使用相同的计划,并消除了参数嗅探的可能性。一旦这样做,并确定它没有帮助,那么可能就可以安全地消除参数嗅探。


1

也许尝试强制执行顺序,所以您可能总是从较小的表(变量)开始。但是,这对于视图来说很棘手...

    SELECT  -- lots of fields
    FROM    @LocationIds [b] WITH (NOEXPAND)
            INNER JOIN  [dbo].[ListingSearchView][a] WITH (NOEXPAND) 
                ON [a].[LocationId] = [b].[Id]
    WHERE   [a].[StatusType] = @statusType
    OPTION (FORCE ORDER);

或者您也可以强制执行循环联接,如果这通常是您希望将表变量联接到视图的方式,这也会强制执行顺序...

    SELECT  -- lots of fields
    FROM    @LocationIds [b] WITH (NOEXPAND)
            INNER LOOP JOIN  [dbo].[ListingSearchView][a] WITH (NOEXPAND) 
                ON [a].[LocationId] = [b].[Id]
    WHERE   [a].[StatusType] = @statusType
    --leaving this here so you don't get an annoying warning 
    OPTION (FORCE ORDER);

0

在查询编辑器中输入存储过程的名称,然后选择存储过程。命名并选择显示估计的执行计划,或单击(Ctrl + L)。下面这个形象。

显示估计执行计划的图像

然后执行计划将显示在查询编辑器底部的“消息”选项卡旁边。然后在绿色线条中显示缺少的索引详细信息,然后右键单击该详细信息。然后在新选项卡中打开新查询,然后创建索引。然后您的查询运行很快。

因此,我将这种方法用于诊断工作缓慢的查询。还有很多查询或方法可以使用。

详细执行计划


-1

如果您认为问题出在阻塞中,建议您使用乐观的事务隔离级别“读取已提交的快照”(请注意,这将增加tempDB的开销)。

参考: https : //docs.microsoft.com/zh-cn/dotnet/framework/data/adonet/sql/snapshot-isolation-in-sql-server

如果问题不在读/写阻塞中,则可以尝试在视图上添加索引(索引的最佳选择取决于数据的选择性)

CREATE NONCLUSTERED INDEX IX_ListingSearchView (LocationID, StatusType) INCLUDE (other columns...)

1
您建议的索引已经存在IX_ListingSearchView_ForAPI(请参阅问题中的脚本)。
保罗·怀特说GoFundMonica

1
嘿,谢谢你的回答。正如我在问题中所说的那样,在应用修复程序之前,我想知道问题出在哪里。否则我可能只是忽略了真正的问题。我的问题是首先找到问题,然后找到正确的解决方案。
RPM1984

您能否在本地环境中获得该慢查询?如果同一查询有时运行缓慢,有时运行很快,则可能取决于输入参数。您能否提供逻辑读取的数目以及慢查询返回的总行数。
Artashes Khachatryan

@ArtashesKhachatryan是的,它有时在本地也会运行缓慢。我已经用执行计划更新了问题。我想知道它是否与慢查询(返回的行)比快查询(返回的行)有关。
RPM1984 '10 -10-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.