Рекомендации по диагностике «иногда» медленного запроса

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

Я включил трассировку профайлера с XML-статистикой showplan.

Вот медленный (6 секунд) и соответствующий план: введите описание изображения здесь

Выглядит точно так, как я ожидал, и тот же план, когда запрос быстрый.

Вот увеличение дорогостоящей части плана, если это поможет: введите описание изображения здесь

Вот полная схема просмотра / поддержки таблиц, если это поможет: https://pastebin.com/wh1sRcbQ

Примечания:

  • Индексы были дефрагментированы, статистика актуальна.
  • Первоначально запрос был встроен в представление, но я перешел в SPROC, чтобы попытаться помочь в стабилизации. Не помогло
  • Добавление WITH OPTION (RECOMPILE);подсказки (не сработало, поэтому не может быть сниффинг параметров?)
  • Другие запросы в системе также иногда выполняются медленно, и у них также нет очевидных проблем в их плане.
  • Может быть блокировка? Не уверен, как подтвердить.

Любые идеи о том, что я мог бы попробовать дальше?

Благодарность

RPM1984
источник
1
Комментарии не для расширенного обсуждения; этот разговор был перенесен в чат . Все: Пожалуйста, используйте эту возможность для дальнейшего обсуждения этого вопроса.
Пол Уайт говорит, что GoFundMonica
данная ссылка не работает. Запрос запроса прямой, существует большое различие между фактическим и предполагаемым количеством строк, что вызывает озабоченность. Я думаю, что проблема заключается в запросе представления. Я думаю, что недостаточно данных. Это должно быть близко
KumarHarsh
Вы пытались запустить WhoIsActive (от Адама Мачаника) во время выполнения запроса? whoisactive.com Содержит информацию о задачах ожидания, которая должна указывать вам правильное направление.
MJH
Вы устранили что-то внешнее по отношению к БД, вызвав это. Возможно, какое-то другое приложение вызывает синхронный ввод-вывод в хранилище, совместно используемое с БД?
Йохан

Ответы:

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

Запишите имя процедуры Store в редакторе запросов, затем выберите процедуру Store. имя и затем выберите Показать план предполагаемого выполнения или нажмите (Ctrl + L). под изображением этого.

Изображение отображения предполагаемого плана выполнения

затем планы выполнения отображаются рядом с вкладкой «Сообщения» в нижней части редактора запросов. затем в зеленых цветных линиях покажите недостающие детали индекса и щелкните по нему правой кнопкой мыши. Затем Новый запрос откройте в новой вкладке, затем создайте ИНДЕКС. тогда ваш запрос выполняется быстро.

Поэтому я использовал этот метод для диагностики запросов, которые работают медленно. а также есть так много запросов или методов, которые вы можете использовать.

План выполнения с деталями

rks_dotnet
источник
-1

Если вы считаете, что проблема заключается в блокировке, я предлагаю вам использовать оптимистический уровень изоляции транзакции Read Committed Snapshot (имейте в виду, что это приведет к накладным расходам на вашу базу данных tempDB).

СПРАВКА: https://docs.microsoft.com/en-us/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
Можете ли вы получить этот медленный запрос в вашей локальной среде? Если один и тот же запрос иногда выполняется медленно, а иногда быстро, это может зависеть от входных параметров. Можете ли вы указать количество логических чтений и общее количество строк, возвращаемых вашим медленным запросом.
Арташес Хачатрян
@ArtashesKhachatryan да, иногда он работает медленно и на местном. Я обновил вопрос с планом выполнения. Мне интересно, связано ли это с медленными запросами, возвращающими больше строк, чем быстрыми, как вы сказали.
RPM1984