Cela peut sembler une question très fondamentale, et même cela devrait être. Cependant, comme ventilateur de la méthode scientifique, j'aime créer une hypothèse, puis le tester pour voir si je suis correct. Dans ce cas, j'essaie de mieux comprendre la production de sys.dm_exec_sessions
, et plus précisément, la colonne unique "lit".
Les livres SQL Server en ligne le spécifient plutôt schmiquement comme suit:
Nombre de lectures effectuées, selon les demandes de cette session, au cours de cette session. N'est pas nullable.
On pourrait supposer que cela indiquerait le nombre de pages Lire du 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.
Le logical_reads
colonne dans la même table est définie comme suit:
Nombre de lectures logiques effectuées à la session. N'est pas nullable.
De l'expérience en utilisant SQL Server, je pense que cette colonne reflète le nombre de pages qui ont été lues à la fois à partir du disque et en mémoire . En d'autres termes, le nombre total de pages jamais Lisez par la session, peu importe où ces pages résident. Le différentiel, ou la proposition de valeur, d'avoir deux colonnes distinctes offrant des informations similaires. semble-t-il Pour que l'on puisse comprendre le rapport des pages lues à partir du disque (reads
) vs ceux lus dans le cache tampon (logical_reads
) Pour une session spécifique.
Sur ma plate-forme d'essai, j'ai créé une nouvelle base de données créée une seule table avec un nombre connu de pages de données, puis lisez ce tableau dans une nouvelle session. Puis j'ai regardé sys.dm_exec_sessions
Pour voir ce que la reads
et logical_reads
Colonnes a dit à propos de la session. À ce stade, je suis confondu par les résultats. Peut-être que quelqu'un ici peut éclairer cela pour moi pour moi.
La plate-forme 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;
La première instruction SELECT ci-dessus montre qu'en fait, la table est composée de 10 000 lignes, avec 5 025 pages totales, 5 020 pages utilisées et 5 000 pages de données; précisément comme on pourrait s'attendre:
La deuxième instruction SELECT confirme que nous n'avons rien en mémoire pour la table TestReads
.
Dans un nouvelle session , nous faisons la requête suivante, prenant note de la session_id:
USE TestReads;
SET STATISTICS IO ON;
SELECT *
FROM dbo.TestReads;
Comme on pourrait s'y attendre, cela lit toute la table du disque en 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 un , troisième , 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'attendrais à voir sys.dm_exec_sessions
show au moins 5 000 pour les deux reads
et logical_reads
. Hélas, je vois reads
montre zéro. logical_reads
montre un nombre attendu de lecture quelque part au nord de 5 000 - il montre 5 020 dans mon test:
Je sais que SQL Server lit toute la table TestReads
dans la mémoire, en vertu du 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 résultats:
Si je cours ce qui suit:
SELECT des.session_id
, des.reads
, des.logical_reads
FROM sys.dm_exec_sessions des
Je vois reads
de 784 à la session où je crée la plate-forme de test; Cependant, toutes les autres sessions montrent zéro dans la colonne reads
.
J'ai maintenant mis à jour mon instance de test SQL Server à 11.0.6020; Cependant, le résultat est le même.
Ma compréhension a toujours été que reads
n'est que physique (c'est-à-dire du disque) et logical_reads
est seulement à partir du piscine tampon (c'est-à-dire de la mémoire). J'ai fait un test rapide avec une table plus petite 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, c'est que vous ne nettoyez pas la mémoire. Vous devez exécuter les suivants entre les tests pour la forcer à recharger à partir du disque:
DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS;
Ma configuration de test était la suivante:
CREATE TABLE dbo.ReadTest (Col1 CHAR(7500) DEFAULT (' '));
INSERT INTO dbo.ReadTest (Col1) VALUES (DEFAULT), (DEFAULT);
J'ai ensuite couru ce qui suit:
SELECT reads, logical_reads FROM sys.dm_exec_sessions WHERE session_id = @@SPID;
SELECT * FROM dbo.ReadTest;
(Oui, je testais dans la même session que j'exécutais le DMV dans, mais cela n'a pas rakew les résultats pour le champ reads
, et si rien d'autre, n'était au moins cohérent s'il contribuait à les logical_reads
domaine.)
Pour tester, j'exécuterais la commande DBCC, puis les deux requêtes SELECT. Ensuite, je verrais un saut dans les deux reads
et logical_reads
des champs. Je voudrais exécuter les requêtes Sélectionner à nouveau et parfois je verrais un saut supplémentaire dans reads
.
Après cela, j'exécuterais les deux requêtes sélectionnées plusieurs fois et le reads
resterait la même alors que le logical_reads
monta 4 chaque fois.
Je commencerais ensuite à exécuter le DBCC et à voir ce même motif. Je l'ai fait plusieurs fois et les chiffres rapportés étaient conformes à tous les essais.
Plus d'informations:
Je teste également sur SQL Server 2012, SP2 - 64 BIT (11.0.5343).
Les commandes DBCC suivantes nous avons à la fois éprouvées et n'ont aucun effet:
DBCC FREESYSTEMCACHE('ALL');
DBCC FREEPROCCACHE;
DBCC FREESESSIONCACHE;
Le plus souvent DBCC DROPCLEANBUFFERS
fonctionne, mais je vois de temps en temps qu'il est toujours dans la piscine tampon. Impair.
Quand je:
DBCC DROPCLEANBUFFERS
: Les lectures montent par 24 et logical_reads montent par 52.SELECT [Col1] FROM dbo.ReadTest;
Encore une fois: les lectures ne montent pas, mais logical_reads montent par 6.DBCC DROPCLEANBUFFERS
).Il semblerait que les 52 représentent des comptes logiques pour la génération de plans et les résultats, ce qui implique que la génération de plan a provoqué les 46 lectures logiques supplémentaires. Mais les lectures physiques ne montaient pas à nouveau et pourtant, il est identique 52 lectures logiques que lorsqu'il avait besoin de faire les lectures physiques, donc logical_reads
n'inclut pas le physique reads
. Je suis juste en train de faire clairement clairement, qu'il soit indiqué ou implicite dans la question.
Mais, un comportement que j'ai constaté que je constate que, 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, cela devrait être parti. Mais attendez quelques minutes et cela se présente à nouveau, mais cette fois-ci sans toutes les pages de données. Dans mon test, la table contient 1 page IAM et 4 pages de données. Les 5 pages sont dans la piscine tampon après que je faisais le SELECT
. Mais quand il est rechargé par un autre processus, c'est juste la page IAM et 1 page de données. Je pensais que cela pourrait être SSMS IntelliSense, mais j'ai supprimé toutes les références à ce nom d'objet dans mon onglet de requête et qu'il est toujours rechargé.