O operador usou o tempdb para espalhar dados durante a execução com o nível 2 de derramamento

16

Estou lutando para minimizar o custo da operação de classificação em um plano de consulta com o aviso Operator usedtempdbto spill data during execution with spill level 2

Eu encontrei várias postagens relacionadas a dados de derramamento durante a execução com o nível 1 de derramamento , mas não o nível 2. O nível 1 parece ser causado por estatísticas desatualizadas , e o nível 2? Não encontrei nada relacionado a level 2.

Achei este artigo muito interessante relacionado aos avisos de classificação:

Nunca ignorar um aviso de classificação no SQL Server

Meu servidor sql?

Microsoft SQL Server 2014 (SP2) (KB3171021) - 12.0.5000.0 (X64) 17 de junho de 2016 19:14:09 Copyright (c) Microsoft Corporation Enterprise Edition (64 bits) no Windows NT 6.3 (Build 9600:) (Hypervisor)

Meu hardware?

executando a consulta abaixo para encontrar o harware:

- Informações de hardware do SQL Server 2012

SELECT cpu_count AS [Logical CPU Count], hyperthread_ratio AS [Hyperthread Ratio],
cpu_count/hyperthread_ratio AS [Physical CPU Count], 
physical_memory_kb/1024 AS [Physical Memory (MB)], affinity_type_desc, 
virtual_machine_type_desc, sqlserver_start_time
FROM sys.dm_os_sys_info WITH (NOLOCK) OPTION (RECOMPILE);

insira a descrição da imagem aqui

memória atualmente alocada

SELECT
(physical_memory_in_use_kb/1024) AS Memory_usedby_Sqlserver_MB,
(locked_page_allocations_kb/1024) AS Locked_pages_used_Sqlserver_MB,
(total_virtual_address_space_kb/1024) AS Total_VAS_in_MB,
process_physical_memory_low,
process_virtual_memory_low
FROM sys.dm_os_process_memory;

insira a descrição da imagem aqui

quando executo minha consulta com escopo de um ano, não recebo nenhum aviso, conforme a imagem abaixo:

insira a descrição da imagem aqui

Mas quando eu o executo apenas no escopo de 1 dia, recebo este aviso on the sort operator:

insira a descrição da imagem aqui

esta é a consulta:

    DECLARE @FromDate SMALLDATETIME = '19-OCT-2016 11:00'
    DECLARE @ToDate   SMALLDATETIME = '20-OCT-2016 12:00'




    SELECT      DISTINCT
                a.strAccountCode ,
                a.strAddressLine6 ,
                a.strPostalCode ,
                CASE    WHEN a.strCountryCode IN ('91','92') THEN 'GB-Int'
                        ELSE a.strCountryCode
                        END AS [strCountryCode]
    FROM        Bocss2.dbo.tblBAccountParticipant AS ap
    INNER JOIN  Bocss2.dbo.tblBAccountParticipantAddress AS apa ON ap.lngParticipantID = apa.lngParticipantID
                                                                AND apa.sintAddressTypeID = 2
    INNER JOIN  Bocss2.dbo.tblBAccountHolder AS ah ON ap.lngParticipantID = ah.lngParticipantID
    INNER JOIN  Bocss2.dbo.tblBAddress AS a ON apa.lngAddressID = a.lngAddressID
                                            AND a.blnIsCurrent = 1
    INNER JOIN  Bocss2.dbo.tblBOrder AS o ON ap.lngParticipantID = o.lngAccountParticipantID
                                        AND o.sdtmOrdCreated >= @FromDate
                                        AND o.sdtmOrdCreated < @ToDate

OPTION(RECOMPILE)

o plano de consulta está aqui

o plano de consulta usando pastetheplan

Perguntas: 1) no plano de consulta, vejo o seguinte:

StatementOptmEarlyAbortReason="GoodEnoughPlanFound" CardinalityEstimationModelVersion="70" 

por que 70? Estou usando o sql server 2014

2) como me livrar desse operador de classificação (se possível)?

3) Vi a expectativa de vida da página bastante baixa, além de adicionar mais memória a esse servidor. Existe alguma outra coisa em que posso dar uma olhada para ver se consigo evitar esse aviso?

Felicidades

Atualização após a resposta de Shanky e Paul White

Verifiquei minhas estatísticas de acordo com o script abaixo e elas parecem todas corretas e atualizadas.

estes são todos os índices e tabelas usados ​​nesta consulta.

DBCC SHOW_STATISTICS ('dbo.tblBAddress','IDXF_tblBAddress_lngAddressID__INC')
GO
DBCC SHOW_STATISTICS  ('dbo.tblBOrder','IX_tblBOrder_sdtmOrdCreated_INCL')
GO
DBCC SHOW_STATISTICS ('dbo.tblBAccountHolder','PK_tblAccountHolder')
GO
DBCC SHOW_STATISTICS ('dbo.tblBAccountParticipant','PK_tblBAccountParticipants')
GO
DBCC SHOW_STATISTICS ('dbo.tblBAccountParticipantAddress','IDXF_tblBAccountParticipantAddress_lngParticipantID')
GO

é isso que eu voltei:

insira a descrição da imagem aqui

insira a descrição da imagem aqui

Este é um resultado parcial, mas eu os visitei novamente.

Para atualização de estatísticas, atualmente tenho Ola Hallengren

o trabalho de otimização de índice - programado para ser executado uma vez por semana - domingos

EXECUTE [dbo].[IndexOptimize] 
@Databases = 'USER_DATABASES,-%Archive', 
@Indexes = 'ALL_INDEXES' , 
@FragmentationLow = NULL,
@FragmentationMedium = NULL,
@FragmentationHigh = NULL,
@PageCountLevel=1000,
@StatisticsSample =100
,@UpdateStatistics = 'Index', 
@OnlyModifiedStatistics = 'Y',
@TimeLimit=10800, 
@LogToTable = 'Y'

Embora as estatísticas pareçam ser atualizadas Depois de executar o script a seguir, não recebi mais aviso no operador de classificação.

UPDATE STATISTICS [Bocss2].[dbo].[tblBOrder]  WITH FULLSCAN
--1 hour  04 min 14 sec

UPDATE STATISTICS [Bocss2].[dbo].tblBAddress  WITH FULLSCAN
-- 45 min 29 sec

UPDATE STATISTICS  [Bocss2].[dbo].tblBAccountHolder WITH FULLSCAN
-- 26 SEC

UPDATE STATISTICS  [Bocss2].[dbo].tblBAccountParticipant WITH FULLSCAN
-- 4 min

UPDATE STATISTICS  [Bocss2].[dbo].tblBAccountParticipantAddress WITH FULLSCAN
-- 7 min 3 sec
Marcello Miorelli
fonte
Quanto foi reduzido o tempo de consulta?
Influente
Eu nunca poderia implementar uma solução que me permitisse manter as estatísticas atualizadas em tabelas tão grandes. A solução seria particionar as tabelas e usar estatísticas de incremento, mas nunca desci para implementá-las porque deixei o empregador. Algo que eu adoraria ter implementado.
Marcello Miorelli 6/07

Respostas:

17

e o nível 2? Não encontrei nada relacionado ao nível 2.

De acordo com este documento antigo do MS, o número no derramamento Tempdb significa quantas passagens são necessárias nos dados para classificá-los. Portanto, o Derramamento 1 significa que precisa passar 1 vez para classificar os dados e 2 significa que precisa passar 2 vezes.

Citando no blog:

Se uma consulta que envolve uma operação de classificação gerar uma classe de eventos de avisos de classificação com um valor de nível de derramamento igual a 2, o desempenho da consulta poderá ser afetado porque são necessárias várias passagens sobre os dados para classificá-los. No exemplo abaixo, vemos um valor de nível de derramamento de 1, significando que uma passagem sobre os dados foi suficiente para concluir a classificação.

por que 70? Estou usando o sql server 2014

Isso ocorre porque o nível de compatibilidade do banco de dados na imagem NÃO é 120 (o que significa nível de compatibilidade do banco de dados de 2014), pois não é uma consulta 120 que será processada usando o modelo antigo de estimativa de cardinalidade (CE), que é conhecido como CardinalityEstimationModelVersion="70". Estou certo de que você está ciente de que, no SQL Server 2014, temos o novo CE.

como me livrar desse operador de classificação (se possível)?

O comando distinto que você está usando está causando a operação de classificação. Os dados que estão sendo classificados não cabem na memória, portanto são derramados no tempdb e, quando isso acontece, um aviso de classificação com ponto de exclamação amarelo é fornecido no plano de execução. Os avisos de classificação nem sempre são um problema.

Você pode ver no plano de execução que o número estimado de linhas a serem classificadas é 1, mas 16.353 são encontrados no tempo de execução. A quantidade de memória reservada para a classificação é baseada na expectativa de tamanho (estimado) da entrada e não pode aumentar durante a execução (neste caso).

A pequena concessão de memória para a consulta (1632 KB) também é compartilhada entre operadores que consomem memória em execução simultânea ( junções de loop de classificação e 'otimizadas' ). No seu plano, isso significa que 33,33% (544 KB) estão disponíveis para a classificação durante a leitura de linhas (fração da memória de entrada). Como não há memória suficiente para classificar as 16.353 linhas, ela se espalha para tempdb . Um derramamento de nível único não é suficiente para concluir a classificação; portanto, é necessário um segundo nível de derramamento (consulte a referência no final para obter mais detalhes sobre os níveis de derramamento).

Classificar propriedades

Classifique as propriedades conforme exibidas no SQL Sentry Plan Explorer

A atualização das estatísticas provavelmente ajudará no problema de estimativa de cardinalidade. Você pode estar enfrentando o problema principal crescente, especialmente na mesa tblBOrder. Uma simples seleção dessa tabela com as datas literais da sua pergunta provavelmente estimará uma linha agora.

Vi a expectativa de vida útil da página bastante baixa, além de adicionar mais memória a esse servidor. Existe alguma outra coisa em que posso dar uma olhada para ver se posso evitar esse aviso?

PLE é indicação da quantidade de atividade de E / S, aumentou? Isso acontece com freqüência ou apenas quando você executa uma determinada consulta ou ocorre apenas hoje. Evite reações bruscas, primeiro precisamos ter certeza de que você realmente está enfrentando pressão de memória ou alguma consulta não autorizada que esteja gerando muita E / S está causando isso. De qualquer forma, você já tem 97 G de memória atribuída ao SQL Server.

Para obter mais informações sobre os níveis de derramamento e o principal problema crescente, consulte:

Shanky
fonte