Potrebbe sembrare una domanda basilare, e in effetti dovrebbe esserlo. Tuttavia, come fan del metodo scientifico, mi piace creare un'ipotesi, quindi testarla per vedere se ho ragione. In questo caso, sto cercando di capire meglio l'output sys.dm_exec_sessions
e, più specificamente, la singola colonna "legge".
La documentazione in linea di SQL Server specifica in modo piuttosto secco questo come:
Numero di letture eseguite, da richieste in questa sessione, durante questa sessione. Non è nullable.
Si potrebbe presumere che ciò indichi il numero di pagine lette dal disco per soddisfare le richieste emesse da questa sessione dall'inizio della sessione. Questa è l'ipotesi che ho pensato di testare.
La logical_reads
colonna nella stessa tabella è definita come:
Numero di letture logiche eseguite nella sessione. Non è nullable.
Per esperienza con SQL Server, credo che questa colonna rifletta il numero di pagine che sono state lette sia dal disco che in memoria . In altre parole, il numero totale di pagine mai lette dalla sessione, indipendentemente da dove risiedano quelle pagine. Il differenziatore, o proposizione di valore, di avere due colonne separate che offrono informazioni simili sembrerebbe essere quello di capire il rapporto tra le pagine lette dal disco ( reads
) rispetto a quelle lette dalla cache del buffer ( logical_reads
) per una sessione specifica.
Sul mio banco di prova, ho creato un nuovo database, creato una singola tabella con un numero noto di pagine di dati, quindi ho letto quella tabella in una nuova sessione. Poi ho guardato sys.dm_exec_sessions
per vedere cosa dicevano le colonne reads
e logical_reads
sulla sessione. A questo punto sono confuso dai risultati. Forse qualcuno qui può far luce su questo per me.
Il banco prova:
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 prima istruzione selezionata sopra mostra che in realtà la tabella è composta da 10.000 righe, con 5.025 pagine totali, 5.020 pagine utilizzate e 5.000 pagine di dati; esattamente come ci si aspetterebbe:
La seconda istruzione select conferma che non abbiamo nulla in memoria per la TestReads
tabella.
In una nuova sessione , eseguiamo la seguente query, prendendo atto del session_id:
USE TestReads;
SET STATISTICS IO ON;
SELECT *
FROM dbo.TestReads;
Come ci si aspetterebbe, questo legge l'intera tabella dal disco in memoria, come mostrato nell'output di 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.
In una terza sessione, controlliamo 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 */
Mi aspetto di vedere almeno 5.000 sys.dm_exec_sessions
spettacoli per entrambi e . Ahimè, vedo mostra zero. mostra un numero previsto di letture da qualche parte a nord di 5.000 - mostra 5.020 nel mio test:reads
logical_reads
reads
logical_reads
So che SQL Server ha letto l'intera TestReads
tabella in memoria, in virtù del 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;
Che cosa sto facendo di sbagliato?
Sto usando SQL Server 2012 11.0.5343 per questo test.
Ulteriori risultati:
Se eseguo quanto segue:
SELECT des.session_id
, des.reads
, des.logical_reads
FROM sys.dm_exec_sessions des
Vedo reads
784 nella sessione in cui sto creando il banco prova; tuttavia tutte le altre sessioni mostrano zero nella reads
colonna.
Ora ho aggiornato la mia istanza di test di SQL Server a 11.0.6020; tuttavia il risultato è lo stesso.
SET STATISTICS IO ON
poco prima che leggessi dalla tabella nella seconda sessione, riporta 3 letture fisiche e 4998 letture read-ahead; tuttavia sys.dm_exec_sessions
non riflette ancora quello nella reads
colonna.
STATISTICS IO
i.stack.imgur.com/XbHae.png
reads
campi. Ho il sospetto che funzioni in modo simile a session_space_usage o qualunque altro DMV che mostri l'utilizzo di tempdb per sessione che non si incrementa fino al termine della "richiesta".
sys.dm_exec_requests
ti darà quasi lo stesso deiset statistics io on
risultati.