J'ai quelques questions sur le fonctionnement de la mise en cache des données
Imaginez que nous avons ci-dessous la situation:
Le serveur a redémarré ou nous venons d'exécuter DBCC DROPCLEANBUFFERS
Nous avons un Table1
soit 50 Go et contient les colonnes A
, B
, C
, D
, E
.
La colonne A
est une clé d'index cluster, les colonnes B
et C
ont des index non clusterisés.
Quand on fait
select top 100 * from Table1
l'index cluster (table) est-il lu en entier du disque à la mémoire, même si nous n'avons besoin que de 100 lignes? Ou bien seulement 100 lignes (leurs pages de données) sont-elles lues du disque vers la mémoire?
Idem avec l'index non clusterisé, quand nous le faisons
select top 100 * from Table1 where column B = 'some value'
l'ensemble de l'index non clusterisé + index clusterisé est-il chargé en mémoire? Ou seulement 100 lignes de l'index non cluster et 100 lignes de l'index cluster?
Données de test
CREATE TABLE dbo.Table1( A INT IDENTITY(1,1) PRIMARY KEY NOT NULL
,B varchar(255),C int,D int,E int);
INSERT INTO dbo.Table1 WITH(TABLOCK)
(B,C,D,E)
SELECT TOP(1000000) 'Some Value ' + CAST((ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) % 400) as varchar(255))-- 400 different values
,ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
,ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
,ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
FROM master..spt_values spt1
CROSS APPLY master..spt_values spt2;
CREATE INDEX IX_B
On dbo.Table1(B);
CREATE INDEX IX_C
On dbo.Table1(C);
Lorsque nous "sélectionnons les 100 premiers * de Table1" - l'index en cluster entier (table) est lu du disque à la mémoire, même si nous avons besoin de seulement 100 lignes? ou seulement 100 lignes (leurs pages de données) sont lues du disque vers la mémoire?
Seules 100 lignes de l'index cluster sont lues. Par conséquent, seules leurs pages de données sont mises en cache dans la mémoire.
Exemple
Dans mon cas, il lit vers le bas à partir de l'index clusterisé, 1 à 100 valeurs pour la colonne A
.
SET STATISTICS IO, TIME ON;
select top 100 * from dbo.Table1
Le lit:
Table 'Table1'. Scan count 1, logical reads 4, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
4 lectures logiques = 4 pages
Pourquoi voyons-nous encore un scan count = 1
, mais, seulement 4
lectures logiques que vous pourriez demander?
Parce qu'il exécute un balayage de plage :
pour satisfaire l'opérateur supérieur.
De même avec un index non clusterisé, lorsque nous "sélectionnons les 100 premiers * du tableau 1 où la colonne B =" une certaine valeur "", l'index non clusterisé entier + index clusterisé est chargé en mémoire? ou seulement 100 lignes de l'index non cluster + 100 lignes de l'index clusterisé?
Exemple 1
SET STATISTICS IO, TIME ON;
select top 100 * from dbo.Table1
WHERE B='Some Value 200'
Vous pouvez vous attendre à ce que l'index non cluster soit utilisé ici, mais en fait, l'index cluster est toujours utilisé:
Avec après avoir vidé le cache 287
lectures logiques & 2528
lire à l'avance lit.
Table 'Table1'. Scan count 1, logical reads 287, physical reads 1, read-ahead reads 2528, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Nous mettons en cache ces lectures de lecture anticipée après les avoir lues sur le disque pour ensuite lire 287
pages de la mémoire.
Le mécanisme de lecture anticipée est la fonctionnalité de SQL Server qui introduit les pages de données dans le cache de tampon avant même que les données ne soient demandées par la requête. Source
Si nous vérifions les pages mises en cache:
cached_pages_count objectname indexname indexid
2536 Table1 PK__Table1__3BD019AE039DA497 1
Nous voyons cela aussi montré.
Donc, dans ce cas, nous mettons en cache quelques pages supplémentaires pour satisfaire la requête plus rapidement, car nous lisons plus de lignes pour leur appliquer un prédicat résiduel:
Mais nous ne lisons ces pages qu'à partir de l'index clusterisé .
Exemple 2
Vous pouvez modifier la requête dans l'espoir d'utiliser l'index non cluster:
select top 100 B from dbo.Table1
WHERE B='Some Value 200';
Ce qu'il fait:
Cela donne à nouveau un petit balayage de portée:
Table 'Table1'. Scan count 1, logical reads 4, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Seules les pages d'index non clusterisées sont chargées ici en mémoire.
Exemple 3
Nous pouvons forcer une recherche de clé pour satisfaire la requête de l'exemple 1 en utilisant un indice:
SET STATISTICS IO, TIME ON;
select top 100 *
from dbo.Table1
WITH(INDEX(IX_B))
WHERE B='Some Value 200';
Cela se traduit à nouveau par des lectures anticipées et des lectures plus logiques que exemple1:
Table 'Table1'. Scan count 1, logical reads 684, physical reads 3, read-ahead reads 465, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Puisque nous effectuons une recherche de clé de l'index non clusterisé vers l'index clusterisé, nous mettrons en cache les pages des deux index:
même si nous avons besoin de seulement 100 lignes? ou seulement 100 lignes (leurs pages de données) sont lues du disque vers la mémoire?
Cela pourrait être dû à l'ordre de traitement logique de la requête SQL car la clause TOP
serait enfin prise en compte dans la séquence logique. pour plus de détails .. . Ainsi, il lirait moins de pages lorsque le filtre serait appliqué dans la clause WHERE
pour ne renvoyer que 100 lignes, sans appliquer TOP 100
.