Pourquoi plus (et un nombre variable de) lectures logiques avec lecture anticipée (prefetch)?

8

Après avoir créé la base de données tpch dans mon SQL Server, j'ai essayé la requête ci-dessous:

    set statistics io on
    DBCC DROPCLEANBUFFERS;        
    select top 100 * from dbo.lineitem order by l_partkey;

La table lineitem a un index non clusterisé sur l_partkey. J'ai émis les requêtes ci-dessus plusieurs fois et j'ai découvert que les lectures logiques varient à chaque fois:

    Table 'lineitem'. Scan count 1, logical reads 1019, physical reads 4, read-ahead reads 1760, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'lineitem'. Scan count 1, logical reads 1007, physical reads 4, read-ahead reads 1720, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'lineitem'. Scan count 1, logical reads 1030, physical reads 4, read-ahead reads 1792, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

De l'article ici: Le nombre de lectures logiques varie , je sais que cela pourrait être causé par un comportement de lecture anticipée.

MAIS exactement pourquoi la lecture anticipée pourrait provoquer des lectures plus logiques? Comment cela change-t-il le comportement de SQL Server? Comme SQL Server peut lire plus de page d'index car il est de toute façon en cache?

Quoi qu'il en soit, j'ai désactivé la lecture anticipée et émettez à nouveau la requête ci-dessus. Maintenant, il rapporte à chaque fois la même quantité de lectures logiques. MAIS les lectures logiques sont beaucoup plus petites !!

    Table 'lineitem'. Scan count 1, logical reads 404, physical reads 160, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Donc, ma question est la suivante: pourquoi la fonction de lecture anticipée peut-elle entraîner de nombreuses lectures logiques supplémentaires?

Par curiosité, j'ai essayé une autre requête sans la "commande par":

    select top 100 * from dbo.lineitem

Voici le résultat sans lire à l'avance:

    Table 'lineitem'. Scan count 1, logical reads 5, physical reads 3, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Voici le résultat avec lecture anticipée:

    Table 'lineitem'. Scan count 1, logical reads 15, physical reads 2, read-ahead reads 3416, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Celui avec lecture anticipée a toujours des lectures plus logiques. Alors pourquoi?

user3610199
la source

Réponses:

9

Le plan de requête de l' ORDER BY l_partkeyexemple lit presque certainement l'index non cluster dans l'ordre (avec lecture anticipée), suivi d'une recherche de clé pour récupérer les colonnes non couvertes.

L'opérateur Nested Loops Join au-dessus de la recherche utilise probablement la prélecture supplémentaire ( WithOrderedPrefetch) pour la recherche. Voir l'article suivant que j'ai écrit pour plus de détails:

En outre, comme je l'ai mentionné en réponse aux questions et réponses liées, le nombre de lectures à lecture anticipée dépend de la synchronisation et des caractéristiques du sous-système de stockage. Le même type de considérations s'applique à la prélecture de recherche lors de la jointure de boucles imbriquées.

Notez que SQL Server émet une lecture anticipée pour les pages qui pourraient être nécessaires à l'analyse d'index, mais cela n'est pas limité par la TOPspécification de la requête. Il TOPs'agit d'un élément de processeur de requêtes, tandis que la lecture anticipée est contrôlée par le moteur de stockage.

Les activités sont assez distinctes: la lecture anticipée (et la prélecture) génère des E / S asynchrones pour les pages qui peuvent être nécessaires au scan (ou à la recherche).

Selon l'ordre dans lequel les E / S se terminent et mettent les lignes à la disposition du processeur de requêtes (entre autres), le nombre de pages réellement touchées (lectures logiques) ou lues physiquement peut varier. Notez en particulier que la recherche anticipée retardée de recherche contribue également aux lectures logiques lorsqu'elle vérifie si une page nécessaire à la recherche est déjà en mémoire ou non.

Ainsi, tout se résume au calendrier détaillé des opérations qui se chevauchent: le processeur de requêtes commencera à fermer le pipeline d'exécution des requêtes dès que le nombre requis de lignes (100) aura été vu sur l'itérateur supérieur. Le nombre d'E / S asynchrones (lecture anticipée ou prélecture) qui auront été émises ou terminées à ce stade est essentiellement non déterministe.

Vous pouvez désactiver la prélecture de jointure de boucles imbriquées avec l' indicateur de trace 8744 pour l'explorer davantage. Cela supprimera la WithOrderedPrefetchpropriété de la jointure des boucles imbriquées. J'utilise habituellement OPTION (QUERYTRACEON 8744)sur la requête elle-même. Dans tous les cas, vous devez vous assurer que vous ne réutilisez pas un plan mis en cache qui a la prélecture. Vider le cache du plan à chaque fois ou forcer une recompilation de requête avec OPTION (RECOMPILE).

Les lectures logiques sont une simple mesure du nombre de pages de cache touchées au nom de la requête. Lorsque la lecture anticipée (et / ou la prélecture) est activée, davantage de pages d'index et de données (et différentes!) Peuvent être touchées afin d'émettre cette lecture anticipée ou dans le cadre de l'activité de prélecture.

Paul White 9
la source