L'opérateur a utilisé tempdb pour déverser des données pendant l'exécution avec le niveau de déversement 2

16

J'ai du mal à minimiser le coût de l'opération de tri sur un plan de requête avec l'avertissement Operator usedtempdbto spill data during execution with spill level 2

J'ai trouvé plusieurs articles liés aux données de déversement lors de l'exécution avec le niveau de déversement 1 , mais pas le niveau 2. Le niveau 1 semble provenir de statistiques obsolètes , qu'en est-il du niveau 2? Je n'ai rien trouvé de semblable level 2.

J'ai trouvé cet article très intéressant concernant les avertissements de tri:

Ne jamais ignorer un avertissement de tri dans SQL Server

Mon serveur SQL?

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

Mon matériel?

exécutez la requête ci-dessous pour trouver le matériel:

- Informations sur le matériel de 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);

entrez la description de l'image ici

mémoire actuellement allouée

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;

entrez la description de l'image ici

lorsque j'exécute ma requête avec une portée d'un an, je ne reçois aucun avertissement, comme le montre l'image ci-dessous:

entrez la description de l'image ici

Mais lorsque je l'exécute uniquement pour une portée d'un jour, j'obtiens cet avertissement on the sort operator:

entrez la description de l'image ici

c'est la requête:

    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)

le plan de requête est ici

le plan de requête en utilisant pastetheplan

Questions: 1) dans le plan de requête, je vois ceci:

StatementOptmEarlyAbortReason="GoodEnoughPlanFound" CardinalityEstimationModelVersion="70" 

pourquoi 70? J'utilise SQL Server 2014

2) comment puis-je me débarrasser de cet opérateur de tri (si possible)?

3) J'ai vu l'espérance de vie des pages assez faible, à part ajouter plus de mémoire à ce serveur, y a-t-il autre chose que je peux voir pour voir si je peux empêcher cet avertissement?

à votre santé

Mise à jour après la réponse de Shanky et Paul White

J'ai vérifié mes statistiques selon le script ci-dessous, et elles semblent toutes correctes et mises à jour.

ce sont tous les index et les tables utilisés dans cette requête.

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

voici ce que je suis retourné:

entrez la description de l'image ici

entrez la description de l'image ici

Ceci est un résultat partiel, mais je les ai tous revus.

Pour la mise à jour des statistiques, j'ai actuellement Ola Hallengren

le travail d'optimisation d'index - planifié une fois par semaine - le dimanche

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'

Bien que les statistiques semblent avoir été mises à jour Après avoir exécuté le script suivant, je n'ai plus d'avertissement sur l'opérateur de tri.

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
la source
Combien le temps de requête a été réduit?
influent
Je ne pourrais jamais implémenter une solution qui me permettrait de garder les statistiques à jour sur de si grandes tables. La solution serait de partitionner les tables et d'utiliser des statistiques incrementao, mais je ne suis jamais descendu pour l'implémenter car j'ai quitté cet employeur. Quelque chose que j'aurais aimé mettre en œuvre cependant.
Marcello Miorelli

Réponses:

17

qu'en est-il du niveau 2? Je n'ai rien trouvé concernant le niveau 2.

Selon cet ancien document MS, le nombre dans le déversement Tempdb signifie combien de passes sont nécessaires sur les données pour trier les données. Donc, Spill 1 signifie qu'il doit passer 1 fois pour trier les données et 2 signifie qu'il doit passer 2 fois.

Citant du blog:

Si une requête impliquant une opération de tri génère une classe d'événements Avertissements de tri avec une valeur de niveau de déversement de 2, les performances de la requête peuvent être affectées car plusieurs passages sur les données sont nécessaires pour trier les données. Dans l'exemple ci-dessous, nous voyons une valeur de niveau de déversement de 1, ce qui signifie qu'un seul passage sur les données était suffisant pour terminer le tri.

pourquoi 70? J'utilise SQL Server 2014

Cela est dû au fait que le niveau de compatibilité de la base de données dans l'image n'est PAS 120 (ce qui signifie le niveau de compatibilité de la base de données 2014) car ce n'est pas 120 que la requête sera traitée en utilisant l'ancien modèle d'estimation de cardinalité (CE) qui est appelé CardinalityEstimationModelVersion="70". Je suis sûr que vous savez que depuis SQL Server 2014, nous avons un nouveau CE.

comment puis-je me débarrasser de cet opérateur de tri (si possible)?

La commande distincte que vous utilisez est à l'origine de l'opération de tri. Les données en cours de tri ne tiennent pas en mémoire, elles sont donc déversées dans tempdb et lorsque cela se produit, un avertissement de tri avec un point d'exclamation jaune est donné dans le plan d'exécution. Les avertissements de tri ne sont pas toujours un problème.

Vous pouvez voir dans le plan d'exécution que le nombre estimé de lignes à trier est de 1, mais 16 353 sont rencontrées au moment de l'exécution. La quantité de mémoire réservée pour le tri est basée sur la taille attendue (estimée) de l'entrée et ne peut pas augmenter pendant l'exécution (dans ce cas).

La petite allocation de mémoire pour la requête (1632 Ko) est également partagée entre les opérateurs gourmands en mémoire exécutant simultanément (tri et jointures de boucle «optimisées» ). Dans votre plan, cela signifie que 33,33% (544 Ko) sont disponibles pour le tri lors de la lecture des lignes (fraction de mémoire d'entrée). Ce n'est pas assez de mémoire pour trier les 16 353 lignes, donc cela déborde sur tempdb . Un déversement à un seul niveau ne suffit pas pour terminer le tri, donc un deuxième niveau de déversement est nécessaire (voir la référence à la fin pour plus de détails sur les niveaux de déversement).

Trier les propriétés

Trier les propriétés affichées dans SQL Sentry Plan Explorer

La mise à jour des statistiques aidera probablement à résoudre le problème d'estimation de la cardinalité. Vous rencontrez peut-être le problème clé croissant, en particulier sur la table tblBOrder. Une simple sélection dans ce tableau avec les dates littérales de votre question estimera probablement une ligne en ce moment.

J'ai vu l'espérance de vie des pages assez faible, à part ajouter plus de mémoire à ce serveur, y a-t-il autre chose que je peux voir pour voir si je peux empêcher cet avertissement?

Le PLE indique la quantité d'activité d'E / S, a-t-il augmenté?. Cela se produit souvent ou uniquement lorsque vous exécutez certaines requêtes ou si cela s'est produit juste aujourd'hui. Évitez la réaction de genou, nous devons d'abord nous assurer que vous êtes vraiment confronté à une pression sur la mémoire ou à une requête voyante qui génère trop d'E / S. Quoi qu'il en soit, vous disposez déjà de 97 G de mémoire attribuée à SQL Server.

Pour plus d'informations sur les niveaux de déversement et le problème clé croissant, voir:

Shanky
la source