web-dev-qa-db-fra.com

Trier les déversements sur tempdb mais les lignes estimées sont égales aux lignes réelles

Sur un SQL Server 2016 SP2 avec une mémoire maximale définie sur 25 Go, nous avons une requête qui s'exécute environ 80 fois en une minute. La requête renverse environ 4000 pages à tempdb. Cela provoque beaucoup de IO sur le disque de tempdb.

Lorsque vous jetez un œil au plan de requête (requête simplifiée), vous verrez que le nombre de lignes estimées est égal au nombre de lignes réelles mais que des déversements se produisent toujours. Les statistiques obsolètes ne peuvent donc pas être la cause du problème.

J'ai fait quelques tests et suivi des déversements de requêtes vers Tempdb:

select id --uniqueidentifier
from SortProblem
where [status] ='A'
order by SequenceNumber asc
option (maxdop 1)

Mais si je sélectionne une autre colonne, aucun déversement ne se produit:

select startdate --datetime
from SortProblem
where [status] ='A'
order by SequenceNumber asc 
option (maxdop 1)

J'ai donc essayé d'agrandir la taille de la colonne id:

select CONVERT(nvarchar(512),id)
from SortProblem
where [status] ='A'
order by SequenceNumber asc 
option (maxdop 1)

Ensuite, aucun déversement ne se produit.

Pourquoi l'identificateur unique se répand-il dans tempdb et dans une colonne datatime? Lorsque je supprime environ 20000 enregistrements, aucun déversement ne se produit également lorsque je sélectionne la colonne id.

Avec le script suivant, vous pouvez reproduire le problème:

CREATE TABLE SortProblem
  (
     id             UNIQUEIDENTIFIER,
     startdate      DATETIME,
     sequencenumber BIGINT,
     status         VARCHAR(50),
     PRIMARY KEY CLUSTERED(id)
  )

SET nocount ON;

WITH nums(num)
     AS (SELECT TOP 103000 ROW_NUMBER()
                             OVER (
                               ORDER BY 1/0)
         FROM   sys.all_objects o1,
                sys.all_objects o2)
INSERT INTO SortProblem
SELECT newid(),
       DATEADD(millisecond, num, GETDATE()),
       num,
       CASE
         WHEN num <= 100000 THEN 'A'
         WHEN num <= 101000 THEN 'B'
         WHEN num <= 102000 THEN 'C'
         WHEN num <= 103000 THEN 'D'
       END
FROM   nums

CREATE NONCLUSTERED INDEX [IX_Status]
  ON [dbo].[SortProblem]([status] ASC)
  INCLUDE ([sequencenumber]) 
15

Activez l'indicateur de trace 7470.

CORRECTIF: l'opérateur de tri se répand dans tempdb dans SQL Server 2012 ou SQL Server 2014 lorsque le nombre estimé de lignes et la taille des lignes sont corrects

Comme je l'ai écrit en réponse à question sur le plan de requête :

Cet indicateur de trace corrige une erreur dans le calcul. Il est assez sûr à utiliser et, à mon avis, devrait être activé par défaut. Le changement est protégé par un indicateur de trace simplement pour éviter les changements de plan inattendus.

14
Paul White 9