Conselhos para diagnosticar uma consulta lenta “às vezes”

20

Eu tenho um procedimento armazenado que retorna resultados de uma exibição indexada por meio de um índice de cobertura. Geralmente, ele é executado rapidamente (~ 10 ms), às vezes pode demorar até 8 segundos.

Aqui está um exemplo de execução aleatória (nota: não é lenta, mas o texto da consulta é o mesmo, exceto o valor passado):

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

Aqui está o 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);

(nota: eu adicionei a OPTION (RECOMPILE)dica recentemente após alguns conselhos, mas não ajudou.

Aqui está o índice de cobertura (observação: a exibição também possui um índice em cluster ListingId, que é único)

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

Coloquei um rastreamento de criador de perfil, com estatísticas XML do showplan.

Aqui está um processo lento (6 segundos) e o plano relevante: insira a descrição da imagem aqui

Parece exatamente como eu esperava e é o mesmo plano quando a consulta é rápida.

Aqui está o zoom na parte cara do plano, se isso ajudar: insira a descrição da imagem aqui

Aqui está o esquema completo das tabelas de visualização / backup, se isso ajudar: https://pastebin.com/wh1sRcbQ

Notas:

  • Os índices foram desfragmentados, as estatísticas atualizadas.
  • Originalmente, a consulta estava embutida na visualização, mas mudei para o SPROC para tentar ajudar a estabilizar. Não ajudou.
  • Adicionando WITH OPTION (RECOMPILE);dica (não funcionou, por isso não pode ser farejador de parâmetros?)
  • Outras consultas no sistema também às vezes são lentas e também não apresentam problemas óbvios em seu plano.
  • Pode estar travando? Não tenho certeza de como confirmar.

Alguma idéia sobre o que eu poderia tentar a seguir?

obrigado

RPM1984
fonte
11
Comentários não são para discussão prolongada; esta conversa foi movida para o bate-papo . Todos: Por favor, use esse recurso para uma discussão mais aprofundada sobre esta questão.
Paul White disse que o GoFundMonica
determinado link não consulta working.proc é sempre em frente, existe um enorme diff entre o número real e estimado de linhas que é a área de concern.I acho mentiras problemáticas em vista query.I acho data.It insuficiente deve ser perto
KumarHarsh
Você tentou executar o WhoIsActive (de Adam Machanic) enquanto a consulta estava em execução? whoisactive.com Inclui informações sobre tarefas em espera, que devem indicar você na direção certa.
MJH
Você eliminou algo externo ao banco de dados que está causando isso. Talvez algum outro aplicativo esteja causando E / S síncrona no armazenamento compartilhado com o banco de dados?
Johan

Respostas:

2

Eu realmente não acho que usar o OPTION (RECOMPILE)é uma maneira eficaz de eliminar a possibilidade de cheirar parâmetros.

A detecção de parâmetros ocorre quando o SQL está confuso sobre uma consulta específica e pensa que é novo porque vê novos parâmetros. É lento porque está demorando mais para gerar um novo plano de execução.

Tudo o que essa opção faz é forçar o SQL a produzir um novo plano sempre que é praticamente a mesma coisa. Em vez disso, você pode considerar adicionar parâmetros padrão usando esta dica:

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

Ao escolher parâmetros para o padrão, certifique-se de usar um conjunto estatisticamente representativo.
Isso forçará o mesmo plano a ser usado todas as vezes e eliminará a possibilidade de detecção de parâmetros. Depois de fazer isso e determinar que não ajudou, provavelmente é seguro descartar o sniffing de parâmetros como uma possibilidade.

Atirador McGavin
fonte
1

Talvez tente forçar a ordem, então você provavelmente está sempre começando com a tabela menor (variável). Isso fica complicado com vistas ...

    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);

ou você pode forçar uma junção de loop, se é geralmente assim que você deseja associar a variável de tabela à visualização, o que também forçará a ordem ...

    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);
Jeremy Giaco
fonte
0

Escreva o nome do procedimento Store no Query Editor e selecione o processo Store. nome e, em seguida, selecione o plano Exibir execução estimada ou clique em (Ctrl + L). abaixo da imagem disso.

Imagem do plano de execução estimada da exibição

os planos de execução são exibidos ao lado da guia Mensagens na parte inferior do Query Editor. nas linhas de cor verde, mostre os detalhes ausentes do índice e clique com o botão direito do mouse. Em seguida, nova consulta é aberta em uma nova guia e cria o índice. sua consulta será executada rapidamente.

Então, eu usei esse método para diagnosticar a consulta que trabalham devagar. e também existem tantas consultas ou métodos que você pode usar.

Plano de execução com detalhes

rks_dotnet
fonte
-1

Se você acha que o problema está no bloqueio, sugiro que você use o Read Optimized Snapshot de nível de isolamento da transação (lembre-se de que isso sobrecarregará o tempDB).

REFERÊNCIA: https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/snapshot-isolation-in-sql-server

Se o problema não está no bloqueio de leitura / gravação, você pode tentar adicionar índices na sua exibição (a melhor escolha de índices depende da seletividade dos seus dados)

CREATE NONCLUSTERED INDEX IX_ListingSearchView (LocationID, StatusType) INCLUDE (other columns...)
Artashes Khachatryan
fonte
11
O índice que você sugere já existe IX_ListingSearchView_ForAPI(veja o script na pergunta).
Paul White diz GoFundMonica
11
Ei, obrigado pela sua resposta. Como já disse na minha pergunta, quero saber qual é o problema antes de aplicar uma correção. Caso contrário, eu poderia apenas estar com vista para o problema real. Minha pergunta é sobre como encontrar o problema primeiro e depois a solução correta.
RPM1984
Você pode obter essa consulta lenta no seu ambiente local? Se a mesma consulta às vezes for lenta e às vezes rápida, pode depender dos parâmetros de entrada. Você pode fornecer o número de leituras lógicas e o número total de linhas retornadas pela sua consulta lenta.
Artashes Khachatryan
@ArtashesKhachatryan sim, às vezes fica lento também no local. Atualizei a pergunta com um plano de execução. Gostaria de saber se está relacionado com as consultas lentas retornando mais linhas do que as rápidas, como você disse.
RPM1984