web-dev-qa-db-fra.com

Comment SQL Server met en cache les données en mémoire

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.

  1. 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?

  2. 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?

6
Aleksey Vitsko

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);

Q1

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 :

enter image description here

enter image description here

pour satisfaire l'opérateur supérieur.


Q2

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é:

enter image description here

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:

enter image description here

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:

enter image description here

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:

enter image description here

8
Randi Vertongen

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.

3
Shekar Kola