L'operatore ha utilizzato tempdb per versare dati durante l'esecuzione con livello di versamento 2


16

Sto lottando per ridurre al minimo il costo dell'operazione di ordinamento su un piano di query con l'avviso Operator usedtempdbto spill data during execution with spill level 2

Ho trovato diversi post relativi ai dati di sversamento durante l'esecuzione con il livello di sversamento 1 , ma non il livello 2. Il livello 1 sembra essere causato da statistiche obsolete , che dire del livello 2? Non sono riuscito a trovare nulla di correlato level 2.

Ho trovato questo articolo molto interessante relativo agli avvisi di ordinamento:

Non ignorare mai un avviso di ordinamento in SQL Server

Il mio server SQL?

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

Il mio hardware?

eseguendo la query di seguito per trovare l'harware:

- Informazioni sull'hardware da 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);

inserisci qui la descrizione dell'immagine

memoria attualmente allocata

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;

inserisci qui la descrizione dell'immagine

quando eseguo la mia query con un anno di validità non ricevo alcun avviso, come nella figura seguente:

inserisci qui la descrizione dell'immagine

Ma quando lo eseguo solo per l'ambito di 1 giorno ricevo questo avviso on the sort operator:

inserisci qui la descrizione dell'immagine

questa è la domanda:

    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)

il piano di query è qui

il piano di query che utilizza pastetheplan

Domande: 1) nel piano di query vedo questo:

StatementOptmEarlyAbortReason="GoodEnoughPlanFound" CardinalityEstimationModelVersion="70" 

perché 70? Sto usando SQL Server 2014

2) come posso eliminare quell'operatore di ordinamento (se possibile)?

3) Ho visto l'aspettativa di vita della pagina piuttosto bassa, a parte l'aggiunta di più memoria a questo server, c'è qualche altra cosa che posso dare un'occhiata per vedere se posso prevenire questo avviso?

Saluti

Aggiornamento dopo la risposta di Shanky e Paul White

Ho controllato le mie statistiche secondo lo script seguente e sembrano tutte corrette e aggiornate.

questi sono tutti gli indici e le tabelle utilizzati in questa query.

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

questo è ciò che mi è stato restituito:

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

Questo è un risultato parziale, ma li ho visitati di nuovo tutti.

Per l'aggiornamento delle statistiche attualmente ho Ola Hallengren

il lavoro di ottimizzazione dell'indice - programmato per essere eseguito una volta alla settimana - la domenica

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'

Anche se le statistiche sembravano essere aggiornate Dopo aver eseguito il seguente script, non ho più ricevuto avvisi sull'operatore di ordinamento.

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

Quanto è stato ridotto il tempo di interrogazione?
influente

Non potrei mai implementare una soluzione che mi consenta di mantenere le statistiche aggiornate su tabelle così grandi. La soluzione sarebbe quella di partizionare le tabelle e usare le statistiche incrementao, ma non sono mai venuto giù per implementarlo perché ho lasciato quel datore di lavoro. Qualcosa che mi piacerebbe aver implementato però.
Marcello Miorelli,

Risposte:


17

che dire del livello 2? Non sono riuscito a trovare nulla correlato al livello 2.

Secondo questo vecchio MS Doc, il numero nella fuoriuscita di Tempdb indica quanti passaggi sono necessari sui dati per ordinare i dati. Quindi Spill 1 significa che deve passare 1 volta per ordinare i dati e 2 significa che deve passare 2 volte.

Citando dal blog:

Se una query che coinvolge un'operazione di ordinamento genera una classe di eventi Avvisi di ordinamento con un valore di livello di versamento pari a 2, le prestazioni della query possono essere influenzate poiché sono necessari più passaggi sui dati per ordinare i dati. Nell'esempio seguente vediamo un valore di livello di versamento pari a 1, il che significa che un passaggio sui dati è stato sufficiente per completare l'ordinamento.

perché 70? Sto usando SQL Server 2014

Questo perché il livello di compatibilità del database nella foto NON è 120 (che indica il livello di compatibilità del database 2014) poiché non è 120 la query verrà elaborata utilizzando il vecchio modello di stima della cardinalità (CE) a cui si fa riferimento CardinalityEstimationModelVersion="70". Sono sicuro che sei consapevole che da SQL Server 2014 abbiamo un nuovo CE.

come posso liberarmi di quell'operatore di ordinamento (se possibile)?

Il comando distinto che stai utilizzando sta causando l'operazione di ordinamento. I dati che vengono ordinati non rientrano nella memoria, quindi vengono riversati in tempdb e quando ciò accade, viene fornito un avviso di ordinamento con un punto esclamativo giallo nel piano di esecuzione. Gli avvisi di ordinamento non sono sempre un problema.

Nel piano di esecuzione è possibile vedere che il numero stimato di righe da ordinare è 1, ma 16.353 sono stati rilevati in fase di esecuzione. La quantità di memoria riservata per l'ordinamento si basa sulla dimensione prevista (stimata) dell'input e non può aumentare durante l'esecuzione (in questo caso).

La piccola concessione di memoria per la query (1632 KB) è anche condivisa tra operatori che consumano contemporaneamente memoria (ordinamento e " loop " ottimizzati ). Nel tuo piano, ciò significa che il 33,33% (544 KB) è disponibile per l'ordinamento durante la lettura delle righe (frazione di memoria di input). Questa memoria non è sufficiente per ordinare le 16.353 righe, quindi si riversa su tempdb . Una fuoriuscita a livello singolo non è sufficiente per completare l'ordinamento, quindi è necessario un secondo livello di fuoriuscita (vedere il riferimento alla fine per maggiori dettagli sui livelli di fuoriuscita).

Ordina proprietà

Ordina le proprietà come visualizzate in SQL Sentry Plan Explorer

L'aggiornamento delle statistiche probabilmente aiuterà con il problema della stima della cardinalità. È possibile che si verifichi il problema chiave crescente, in particolare sulla tabella tblBOrder. Una semplice selezione da quella tabella con le date letterali della tua domanda probabilmente stimerà una riga in questo momento.

Ho visto l'aspettativa di vita della pagina abbastanza bassa, a parte l'aggiunta di più memoria a questo server, c'è qualche altra cosa che posso dare un'occhiata per vedere se posso prevenire questo avviso?

PLE indica la quantità di attività I / O, è aumentato? Quindi ciò accade spesso o solo quando si esegue una determinata query o è successo proprio oggi. Evita la reazione istintiva, per prima cosa dobbiamo assicurarci che tu stia davvero affrontando la pressione della memoria o qualche query canaglia che sta generando troppa I / O che sta causando questo. Ad ogni modo hai già 97 G di memoria assegnata a SQL Server.

Per ulteriori informazioni sui livelli di sversamento e il problema chiave crescente, vedere:

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.