Cela peut sembler une question très fondamentale, et ça devrait l'être. Cependant, en tant que fan de la méthode scientifique, j'aime créer une hypothèse, puis la tester pour voir si j'ai raison. Dans ce cas, j'essaie de mieux comprendre la sortie sys.dm_exec_sessions
, et plus précisément, la colonne unique "lit".
La documentation en ligne de SQL Server spécifie plutôt sèchement ceci:
Nombre de lectures effectuées, par requêtes dans cette session, au cours de cette session. N'est pas annulable.
On pourrait supposer que cela indiquerait le nombre de pages lues sur le disque pour satisfaire les demandes émises par cette session depuis le début de la session. C'est l'hypothèse que je pensais tester.
La logical_reads
colonne de cette même table est définie comme suit:
Nombre de lectures logiques effectuées sur la session. N'est pas annulable.
D'après mon expérience avec SQL Server, je pense que cette colonne reflète le nombre de pages qui ont été lues à la fois sur le disque et en mémoire . En d' autres termes, le nombre total de pages jamais lu par la session, peu importe où ces pages résident. Le différenciateur, ou proposition de valeur, d'avoir deux colonnes distinctes qui offrent des informations similaires semble être que l'on peut comprendre le rapport entre les pages lues sur le disque ( reads
) et celles lues dans le cache de tampon ( logical_reads
) pour une session spécifique.
Sur mon banc de test, j'ai créé une nouvelle base de données, créé une seule table avec un nombre connu de pages de données, puis lu cette table dans une nouvelle session. Ensuite, j'ai regardé sys.dm_exec_sessions
pour voir ce que les colonnes reads
et ont logical_reads
dit sur la session. À ce stade, je suis confus par les résultats. Peut-être que quelqu'un ici peut faire la lumière à ce sujet pour moi.
Le banc d'essai:
USE master;
IF EXISTS (SELECT 1
FROM sys.databases d
WHERE d.name = 'TestReads')
BEGIN
ALTER DATABASE TestReads SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
DROP DATABASE TestReads;
END
GO
CREATE DATABASE TestReads;
GO
ALTER DATABASE TestReads SET RECOVERY SIMPLE;
BACKUP DATABASE TestReads TO DISK = 'NUL:'; /* ensure we are in
simple recovery model */
GO
USE TestReads;
GO
/*
create a table with 2 rows per page, for easy math!
*/
CREATE TABLE dbo.TestReads
(
ID INT NOT NULL
CONSTRAINT PK_TestReads
PRIMARY KEY CLUSTERED
IDENTITY(1,1)
, SomeData CHAR(4000) NOT NULL
);
/*
insert 5000 pages of data
*/
INSERT INTO dbo.TestReads (SomeData)
SELECT TOP(10000) o1.name
FROM sys.objects o1
, sys.objects o2
, sys.objects o3
ORDER BY o1.object_id
, o2.object_id
, o3.object_id;
/*
Verify we have 5,000 pages of data, with 10,000 rows.
*/
SELECT o.name
, p.rows
, au.total_pages
, au.used_pages
, au.data_pages
FROM sys.partitions p
INNER JOIN sys.objects o ON p.object_id = o.object_id
INNER JOIN sys.allocation_units au
ON p.hobt_id = au.container_id
AND (au.type = 1 or au.type = 0)
WHERE p.index_id = 1
AND o.name = 'TestReads'
AND o.type = 'U';
/*
issue a checkpoint to ensure dirty pages are flushed to disk
*/
CHECKPOINT 30;
DBCC DROPCLEANBUFFERS;
DBCC FREESYSTEMCACHE ('ALL');
DBCC FREEPROCCACHE;
DBCC FREESESSIONCACHE;
GO
/*
ensure we have no data cached in memory for the TestReads database
*/
USE master;
ALTER DATABASE TestReads SET OFFLINE WITH ROLLBACK IMMEDIATE;
ALTER DATABASE TestReads SET ONLINE;
SELECT DatabaseName = d.name
, SchemaName = s.name
, ObjectName = o.name
, AllocatedMB = COUNT(1) * 8192E0 / 1048576
, PagesInMemory = COUNT(1)
FROM sys.dm_os_buffer_descriptors dobd
INNER JOIN sys.allocation_units au
ON dobd.allocation_unit_id = au.allocation_unit_id
INNER JOIN sys.partitions p
ON au.container_id = p.hobt_id
AND (au.type = 1 OR au.type = 0)
INNER JOIN sys.objects o ON p.object_id = o.object_id
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
INNER JOIN sys.databases d
ON dobd.database_id = d.database_id
WHERE d.name = 'TestReads'
AND o.name = 'TestReads'
AND o.type = 'U'
GROUP BY d.name
, s.name
, o.name;
Le premier énoncé de sélection ci-dessus montre qu'en fait, le tableau comprend 10 000 lignes, avec 5 025 pages au total, 5 020 pages utilisées et 5 000 pages de données; exactement comme on pourrait s'y attendre:
La deuxième instruction select confirme que nous n'avons rien en mémoire pour la TestReads
table.
Dans une nouvelle session , nous effectuons la requête suivante, en prenant note de la session_id:
USE TestReads;
SET STATISTICS IO ON;
SELECT *
FROM dbo.TestReads;
Comme on pouvait s'y attendre, cela lit la table entière du disque dans la mémoire, comme indiqué dans la sortie de SET STATISTICS IO ON
:
(10000 row(s) affected)
Table 'TestReads'. Scan count 1, logical reads 5020, physical reads 3,
read-ahead reads 4998, lob logical reads 0, lob physical reads 0, lob
read-ahead reads 0.
Dans une troisième session, nous inspectons sys.dm_exec_sessions
:
SELECT des.session_id
, des.reads
, des.logical_reads
FROM sys.dm_exec_sessions des
WHERE des.session_id = 57; /* session_id from the 2nd (previous) session */
Je m'attends à voir au moins 5 000 sys.dm_exec_sessions
spectacles pour et . Hélas, je vois montre zéro. montre un nombre attendu de lectures quelque part au nord de 5 000 - il montre 5 020 dans mon test:reads
logical_reads
reads
logical_reads
Je sais que SQL Server a lu la TestReads
table entière en mémoire, grâce au sys_dm_os_buffer_descriptors
DMV:
USE TestReads;
GO
SELECT DatabaseName = d.name
, SchemaName = s.name
, ObjectName = o.name
, AllocatedMB = COUNT(1) * 8192E0 / 1048576
, PagesInMemory = COUNT(1)
FROM sys.dm_os_buffer_descriptors dobd
INNER JOIN sys.allocation_units au
ON dobd.allocation_unit_id = au.allocation_unit_id
INNER JOIN sys.partitions p
ON au.container_id = p.hobt_id
AND (au.type = 1 OR au.type = 0)
INNER JOIN sys.objects o ON p.object_id = o.object_id
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
INNER JOIN sys.databases d
ON dobd.database_id = d.database_id
WHERE d.name = 'TestReads'
AND o.name = 'TestReads'
AND o.type = 'U'
GROUP BY d.name
, s.name
, o.name;
Qu'est-ce que je fais mal?
J'utilise SQL Server 2012 11.0.5343 pour ce test.
Autres constatations:
Si je lance ce qui suit:
SELECT des.session_id
, des.reads
, des.logical_reads
FROM sys.dm_exec_sessions des
Je vois reads
784 dans la session où je crée le banc d'essai; cependant, toutes les autres sessions affichent zéro dans la reads
colonne.
J'ai maintenant mis à jour mon instance de test SQL Server vers 11.0.6020; cependant le résultat est le même.
la source
sys.dm_exec_requests
vous donnera presque les mêmesset statistics io on
résultats.SET STATISTICS IO ON
juste avant de lire le tableau de la 2e session rapporte 3 lectures physiques et 4998 lectures anticipées; maissys.dm_exec_sessions
ne reflète toujours pas cela dans lareads
colonne.STATISTICS IO
i.stack.imgur.com/XbHae.pngreads
champs. Je soupçonne que cela fonctionne un peu comme session_space_usage ou tout autre DMV qui montre l'utilisation de tempdb par session qui n'augmente pas jusqu'à la fin de la "demande".Réponses:
Ma compréhension a toujours été que ce
reads
n'est que physique (c'est-à-dire à partir du disque) etlogical_reads
uniquement à partir du pool de tampons (c'est-à-dire à partir de la mémoire). J'ai fait un test rapide avec un tableau plus petit qui n'a que 2 pages de données et 3 pages au total, et ce que je vois semble confirmer ces deux définitions.Une chose qui vous donne probablement de mauvais résultats est que vous n'effacez pas la mémoire. Vous devez exécuter ce qui suit entre les tests pour le forcer à recharger à partir du disque:
Ma configuration de test était simplement la suivante:
J'ai ensuite exécuté ce qui suit:
(Oui, je testais au cours de la même session que celle sur laquelle j'exécutais le DMV, mais cela n'a pas faussé les résultats pour le
reads
terrain, et si rien d'autre, était au moins cohérent s'il contribuait aulogical_reads
terrain.)Pour tester, j'exécuterais la commande DBCC puis les deux requêtes SELECT. Ensuite, je verrais un saut dans les champs
reads
etlogical_reads
. Je réexécutais les requêtes SELECT et parfois je voyais un saut supplémentairereads
.Après cela, j'exécuterais les deux requêtes SELECT plusieurs fois et
reads
resterait la même tandis que lalogical_reads
hausse de 4 à chaque fois.Je recommencerais alors avec l'exécution du DBCC et verrais ce même modèle. Je l'ai fait plusieurs fois et les chiffres rapportés étaient cohérents sur toutes les séries de tests.
Plus d'informations:
Je teste également sur SQL Server 2012, SP2 - 64 bits (11.0.5343).
Les commandes DBCC suivantes, nous avons à la fois essayé et vu aucun effet:
La plupart du temps,
DBCC DROPCLEANBUFFERS
cela fonctionne, mais je constate parfois qu'il est toujours dans le pool de tampons. Impair.Quand je:
DBCC DROPCLEANBUFFERS
: Les lectures augmentent de 24 et les lectures_logiques augmentent de 52.SELECT [Col1] FROM dbo.ReadTest;
: les lectures n'augmentent pas, mais les lectures_logiques augmentent de 6.DBCC DROPCLEANBUFFERS
).Il semblerait que les 52 lectures logiques tiennent compte de la génération du plan et des résultats, ce qui implique que la génération du plan a provoqué les 46 lectures logiques supplémentaires. Mais les lectures physiques ne remontent pas et pourtant ce sont les mêmes 52 lectures logiques que c'était quand il fallait aussi faire les lectures physiques, donc
logical_reads
n'inclut pas les physiquesreads
. Je tiens simplement à préciser ce point, qu'il soit ou non énoncé ou sous-entendu dans la Question.MAIS, un comportement que j'ai remarqué qui se déclenche (au moins un peu) en utilisant l'existence des pages de données de la table dans
sys.dm_os_buffer_descriptors
: il est rechargé par un autre processus. Si vous DROPCLEANBUFFERS et vérifiez immédiatement, alors il devrait avoir disparu. Mais attendez quelques minutes et cela réapparaît, mais cette fois sans toutes les pages de données. Dans mon test, le tableau a 1 page IAM et 4 pages de données. Les 5 pages sont dans le pool de tampons après avoir fait leSELECT
. Mais quand il est rechargé par un autre processus, ce n'est que la page IAM et 1 page de données. Je pensais que ce pourrait être SSMS IntelliSense, mais j'ai supprimé toutes les références à ce nom d'objet dans mon onglet de requête et il est toujours rechargé.la source
DBCC DROPCLEANBUFFERS
(et les autresDBCC DROPxxx
commandes) de mon banc de test car ils ne faisaient aucune différence. La mise hors ligne de la base de données supprime tous les tampons et tout le reste associé à la base de données.DBCC FREESYSTEMCACHE ('ALL'); DBCC FREEPROCCACHE; DBCC FREESESSIONCACHE;
CHECKPOUNT
dans le contexte de la base de données avantDBCC DROPCLEANBUFFERS
.