J'ai du mal à minimiser le coût de l'opération de tri sur un plan de requête avec l'avertissement Operator used
tempdbto spill data during execution with spill level 2
J'ai trouvé plusieurs articles liés à données de déversement lors de l'exécution avec niveau de déversement 1 , mais pas au niveau 2. le niveau 1 semble provenir de statistiques obsolètes , qu'en est-il du niveau 2? Je n'ai rien trouvé en rapport avec 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);
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;
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:
Mais lorsque je l'exécute uniquement pour une portée d'un jour, j'obtiens cet avertissement on the sort operator
:
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 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é:
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 reçu 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
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 Sort Warnings 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, la requête sera traitée en utilisant l'ancien modèle d'estimation de cardinalité (CE), appelé CardinalityEstimationModelVersion="70"
. Je suis sûr que vous savez qu'à partir de 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 'optimisé' jointures de boucle). 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 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 de la clé croissante, 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: