Consultas e atualizações extremamente lentas após o IndexOptimize

12

Banco de Dados SQL Server 2017 Enterprise CU16 14.0.3076.1

Recentemente, tentamos mudar dos trabalhos de manutenção padrão do Index Rebuild para o Ola Hallengren IndexOptimize. Os trabalhos de reconstrução de índice padrão estavam em execução há alguns meses sem problemas, e as consultas e atualizações estavam funcionando com tempos de execução aceitáveis. Depois de executar IndexOptimizeno banco de dados:

EXECUTE dbo.IndexOptimize
@Databases = 'USER_DATABASES',
@FragmentationLow = NULL,
@FragmentationMedium = 'INDEX_REORGANIZE,INDEX_REBUILD_ONLINE,INDEX_REBUILD_OFFLINE',
@FragmentationHigh = 'INDEX_REBUILD_ONLINE,INDEX_REBUILD_OFFLINE',
@FragmentationLevel1 = 5,
@FragmentationLevel2 = 30,
@UpdateStatistics = 'ALL',
@OnlyModifiedStatistics = 'Y'

o desempenho foi extremamente degradado. Uma declaração de atualização que levou 100 ms antes IndexOptimizelevou 78.000 ms depois (usando um plano idêntico) e as consultas também estavam executando várias ordens de magnitude piores.

Como esse ainda é um banco de dados de teste (estamos migrando um sistema de produção da Oracle), revertemos para um backup e desativamos IndexOptimizee tudo voltou ao normal.

No entanto, gostaríamos de entender o que IndexOptimizeé diferente do "normal" Index Rebuildque poderia ter causado essa extrema degradação do desempenho para garantir que a evitemos assim que formos para a produção. Qualquer sugestão sobre o que procurar seria muito apreciada.

Plano de execução para a instrução de atualização quando estiver lenta. ie
Após IndexOptimize
plano de execução real (vindo mais cedo possível)

Não consegui perceber a diferença.
Planeje a mesma consulta quando for rápida
Plano de execução real

Martin Bergström
fonte

Respostas:

11

Eu suspeito que você tenha uma taxa de amostragem diferente definida entre suas duas abordagens de manutenção. Acredito que os scripts do Ola usam amostragem padrão, a menos que você especifique o @StatisticsSampleparâmetro , o que não parece o que você está fazendo atualmente.

Neste ponto, isso é especulação, mas você pode verificar para ver qual taxa de amostragem está sendo usada atualmente em suas estatísticas executando a seguinte consulta no banco de dados:

SELECT  OBJECT_SCHEMA_NAME(st.object_id) + '.' + OBJECT_NAME(st.object_id) AS TableName
    ,   col.name AS ColumnName
    ,   st.name AS StatsName
    ,   sp.last_updated
    ,   sp.rows_sampled
    ,   sp.rows
    ,   (1.0*sp.rows_sampled)/(1.0*sp.rows) AS sample_pct
FROM sys.stats st 
    INNER JOIN sys.stats_columns st_col
        ON st.object_id = st_col.object_id
        AND st.stats_id = st_col.stats_id
    INNER JOIN sys.columns col
        ON st_col.object_id = col.object_id
        AND st_col.column_id = col.column_id
    CROSS APPLY sys.dm_db_stats_properties (st.object_id, st.stats_id) sp
ORDER BY 1, 2

Se você perceber que isso está passando por 1s (por exemplo, 100%), é provável que esse seja o seu problema. Talvez tente os scripts do Ola novamente, incluindo o @StatisticsSampleparâmetro com a porcentagem retornada por essa consulta e veja se isso resolve o seu problema?


Como evidência de suporte adicional para essa teoria, o XML do plano de execução mostra taxas de amostragem muito diferentes para a consulta lenta (2,18633%):

<StatisticsInfo LastUpdate="2019-09-01T01:07:46.04" ModificationCount="0" 
    SamplingPercent="2.18233" Statistics="[INDX_UPP_4]" Table="[UPPDRAG]" 
    Schema="[SVALA]" Database="[ulek-sva]" />

Versus a consulta rápida (100%):

<StatisticsInfo LastUpdate="2019-08-25T23:01:05.52" ModificationCount="555" 
    SamplingPercent="100" Statistics="[INDX_UPP_4]" Table="[UPPDRAG]" 
    Schema="[SVALA]" Database="[ulek-sva]" />
John Eisbrener
fonte
@ JoshDarnell LOL, esta é a segunda ocorrência em que você encontrou algumas informações de estatísticas de suporte no plano de consulta que não consegui ver. Obrigado pela edição!
John Eisbrener 03/09/19
Haha eu esqueci que era você, John! Eu prometo que não estou perseguindo você 😅
Josh Darnell
@ JoshDarnell Agradeço os insights adicionais e é outro bom lembrete de que há tanta informação nos planos de execução que você simplesmente não deve pular.
John Eisbrener 03/09/19
Feliz em ajudar! E sim, há coisas que eu sinto falta o tempo todo também (eu fui queimado pelas estatísticas, então eu costumo ir lá rapidamente para ver o que está acontecendo).
Josh Darnell
Obrigado por esta explicação, foi realmente o problema. A maioria das estatísticas tinha uma taxa de amostragem padrão de 2,2%, mas algumas que foram criadas após a migração do Oracle tiveram uma taxa de amostragem de 100%. Parece que a reconstrução do índice padrão manteve os 100%, mas quando usamos o IndexOptimize, aplicamos o padrão de 2,2% também. A aplicação do parâmetro @StatisticsSample e a execução das consultas novamente verificaram que foi isso que causou o problema.
Martin Bergström
5

A resposta de John é a solução correta; isso é apenas uma adição a quais partes do plano de execução foram alteradas e, por exemplo, sobre como identificar facilmente as diferenças com o Sentry One Plan Explorer

Uma declaração de atualização que levou 100 ms antes do IndexOptimize levou 78.000 ms depois (usando um plano idêntico)

Ao analisar todos os planos de consulta quando seu desempenho foi prejudicado, você pode identificar facilmente as diferenças.

Desempenho degradado

insira a descrição da imagem aqui

Duas contagens de mais de 35 segundos de tempo de CPU e tempo decorrido

Desempenho esperado

insira a descrição da imagem aqui

Muito melhor

A principal degradação ocorre duas vezes nesta consulta de atualização:

UPDATE SVALA.INGÅENDEANALYS
                           SET 
                              UPPDRAGAVSLUTAT = @NEW$AVSLUTAT
                        WHERE INGÅENDEANALYS.ID IN 
                           (
                              SELECT IA.ID
                              FROM 
                                 SVALA.INGÅENDEANALYS  AS IA 
                                    JOIN SVALA.INGÅENDEANALYSX  AS IAX 
                                    ON IAX.INGÅENDEANALYS = IA.ID 
                                    JOIN SVALA.ANALYSMATERIAL  AS AM 
                                    ON AM.ID = IA.ANALYSMATERIALID 
                                    JOIN SVALA.ANALYSMATERIALX  AS AMX 
                                    ON AMX.ANALYSMATERIAL = AM.ID 
                                    JOIN SVALA.INSÄNTMATERIAL  AS IM 
                                    ON IM.ID = AM.INSÄNTMATERIALID 
                                    JOIN SVALA.INSÄNTMATERIALX  AS IMX 
                                    ON IMX.INSÄNTMATERIAL = IM.ID
                              WHERE IM.UPPDRAGSID = SVALA.PKGSVALA$STRIPVERSION(@NEW$ID)
                      )

o plano de execução para esta consulta com desempenho degradado

O plano de consulta estimado desta consulta de atualização tem estimativas muito altas quando o desempenho foi degradado:

insira a descrição da imagem aqui

Enquanto na realidade (o plano de execução real) ele ainda tem que funcionar, mas não a quantidade louca que as estimativas mostram.

O maior impacto no desempenho são as duas correspondências de varredura e hash abaixo:

Varredura real com desempenho degradado nº 1

insira a descrição da imagem aqui

Verificação real em desempenho degradado # 2

insira a descrição da imagem aqui


O plano de execução para esta consulta com desempenho esperado

Quando você compara isso às estimativas (ou reais) do plano de consulta com o desempenho esperado normal, as diferenças são fáceis de identificar.

insira a descrição da imagem aqui

Além disso, os dois acessos anteriores à tabela nem aconteceram:

insira a descrição da imagem aqui

insira a descrição da imagem aqui

insira a descrição da imagem aqui

Você não vê essa eliminação na junção de hash porque a entrada de construção (superior) é inserida primeiro na tabela de hash. Posteriormente, os valores zero são analisados ​​nesta tabela de hash, retornando valores zero.

Randi Vertongen
fonte
1
Obrigado pela descrição detalhada dos planos, foi muito útil para minha compreensão do motivo pelo qual o problema ocorreu. Definitivamente vou dar uma olhada no Sentry One Plan Explorer, parece muito útil!
Martin Bergström
@ MartinBergström Isso é ótimo de ouvir, obrigado por fornecer os planos de consulta e por nos fornecer todas as informações relevantes sobre as quais perguntamos nos comentários :). A melhor coisa sobre o explorador de plano é que ele é grátis! Também pode funcionar a partir de ssms internos (clicando com o botão direito do mouse no plano de execução e pressione "ver com o sentryone plan explorer").
Randi Vertongen
1

Sem mais informações, podemos apenas fazer facadas levemente informadas no escuro; portanto, você deve editar a pergunta para fornecer um pouco mais. Por exemplo, os planos de consulta para essa instrução de atualização para a qual você especificou os horários, antes e depois das operações de manutenção do índice, pois os planos podem diferir devido à atualização das estatísticas do índice ( https://www.brentozar.com/pastetheplan / é útil para isso, em vez de preencher a pergunta com o que pode ser um grande pedaço de XML ou fornecer uma captura de tela que não inclui algumas das informações pertinentes que o texto do plano contém).

Dois pontos muito simples do bastão:

  1. A execução de otimização foi definitivamente concluída? Se seus testes estiverem competindo com o pedido de veiculação de reconstruções de longo prazo do índice que afetarão os tempos.
  2. Você testou várias vezes? Se a atualização for baseada em dados de uma consulta que considere muitos dados (em vez de um simples `UPDATE TheTable SET ThisColumn = 'A Static Value'), pode ser que esses dados estejam normalmente na memória, mas tenham sido liberados em nas quais as primeiras execuções de consultas relacionadas serão mais lentas do que o habitual, devido à falha no disco, em vez de encontrar as páginas necessárias já no buffer pool na memória.
David Spillett
fonte
Obrigado por reservar um tempo para responder. Atualizei a pergunta com os links do plano do colar. A otimização definitivamente terminou, durou aproximadamente 1 hora no dia anterior aos problemas. Testamos várias vezes e, na verdade, afetou duas cópias do banco de dados em execução em dois ambientes de teste diferentes da mesma maneira. A declaração de atualização era apenas exemplo o mais simples eu encontrei, havia inúmeras outras inserções e seleciona afetados
Martin Bergström
Por "várias vezes", eu estava tentando tentar as atualizações várias vezes após uma instância do índice ser alterada, em vez de executar o script de otimização de índice várias vezes de forma independente (embora essa seja uma maneira útil de verificar se o resultado é reproduzível). Se a liberação da memória é (ou faz parte) do problema, as primeiras atualizações selecionadas selecionam o buffer pool para que as posteriores sejam potencialmente mais rápidas devido à redução significativa de IO.
David Spillett
Desculpas se minha resposta não foi clara. Sim, tentamos as atualizações várias vezes. As desacelerações ocorreram em um banco de dados usado pelos testadores para testar o aplicativo e as consultas e atualizações foram executadas várias vezes durante o dia sem uma melhoria no desempenho.
Martin Bergström