Estou lutando para minimizar o custo da operação de classificação em um plano de consulta com o aviso Operator used
tempdbto 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);
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;
quando executo minha consulta com escopo de um ano, não recebo nenhum aviso, conforme a imagem abaixo:
Mas quando eu o executo apenas no escopo de 1 dia, recebo este aviso on the sort operator
:
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 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:
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
fonte
Respostas:
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:
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.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).
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.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:
fonte