Cosa indica effettivamente la colonna "reads" in sys.dm_exec_sessions?


10

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_sessionse, 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_readscolonna 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_sessionsper vedere cosa dicevano le colonne readse logical_readssulla 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:

inserisci qui la descrizione dell'immagine

La seconda istruzione select conferma che non abbiamo nulla in memoria per la TestReadstabella.

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_sessionsspettacoli 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:readslogical_readsreadslogical_reads

inserisci qui la descrizione dell'immagine

So che SQL Server ha letto l'intera TestReadstabella in memoria, in virtù del sys_dm_os_buffer_descriptorsDMV:

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;

inserisci qui la descrizione dell'immagine

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 reads784 nella sessione in cui sto creando il banco prova; tuttavia tutte le altre sessioni mostrano zero nella readscolonna.

Ora ho aggiornato la mia istanza di test di SQL Server a 11.0.6020; tuttavia il risultato è lo stesso.


sys.dm_exec_requeststi darà quasi lo stesso dei set statistics io onrisultati.
Kin Shah,

1
Interessante SET STATISTICS IO ONpoco prima che leggessi dalla tabella nella seconda sessione, riporta 3 letture fisiche e 4998 letture read-ahead; tuttavia sys.dm_exec_sessionsnon riflette ancora quello nella readscolonna.
Max Vernon,

2
Nel 2012 vedo spesso 0 sia per le letture che per le letture logiche, nonostante i risultati diversi da zero riportati da STATISTICS IO i.stack.imgur.com/XbHae.png
Martin Smith,

1
In realtà vedo entrambe le colonne zero con il mio approccio su tutte le edizioni che ho testato dal 2008 a SQL2016CTP3
Martin Smith,

1
@MartinSmith e Max: ho anche visto un ritardo in alcuni degli incrementi dei readscampi. 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".
Solomon Rutzky,

Risposte:


2

La mia comprensione è sempre stata che readsè solo fisica (cioè dal disco) ed logical_readsè solo dal pool di buffer (cioè dalla memoria). Ho fatto un rapido test con una tabella più piccola che ha solo 2 pagine di dati e 3 pagine in totale, e quello che vedo sembra confermare quelle due definizioni.

Una cosa che probabilmente ti sta dando cattivi risultati è che non stai cancellando la memoria. È necessario eseguire quanto segue tra i test per forzarlo a ricaricare dal disco:

DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS;

La mia configurazione di test era solo la seguente:

CREATE TABLE dbo.ReadTest (Col1 CHAR(7500) DEFAULT (' '));
INSERT INTO dbo.ReadTest (Col1) VALUES (DEFAULT), (DEFAULT);

Ho quindi eseguito il seguente:

SELECT reads, logical_reads FROM sys.dm_exec_sessions WHERE session_id = @@SPID;
SELECT * FROM dbo.ReadTest;

(Sì, stavo testando nella stessa sessione in cui stavo eseguendo il DMV, ma questo non ha distorto i risultati per il readscampo e, se non altro, è stato almeno coerente se ha contribuito al logical_readscampo.)

Per il test avrei eseguito il comando DBCC e quindi le due query SELECT. Poi vorrei vedere un salto in entrambe le readse logical_readscampi. Eseguivo di nuovo le query SELECT e a volte vedevo un ulteriore salto reads.

Dopodiché, eseguivo le due query SELECT molte volte e readsrimarremmo le stesse mentre logical_readsaumentavano di 4 ogni volta.

Vorrei quindi ricominciare con l'esecuzione del DBCC e vedere lo stesso schema. L'ho fatto parecchie volte e i numeri riportati erano coerenti in tutte le prove.


Ulteriori informazioni:

Sto anche testando su SQL Server 2012, SP2 - 64 bit (11.0.5343).

I seguenti comandi DBCC che abbiamo entrambi provato e non hanno riscontrato alcun effetto:

DBCC FREESYSTEMCACHE('ALL');
DBCC FREEPROCCACHE;
DBCC FREESESSIONCACHE;

Il più delle volte DBCC DROPCLEANBUFFERSfunziona, ma ogni tanto vedo che è ancora nel pool di buffer. Dispari.

Quando io:

  • DBCC DROPCLEANBUFFERS: Le letture aumentano di 24 e il valore logico aumenta di 52.
  • Esegui di SELECT [Col1] FROM dbo.ReadTest;nuovo: le letture non aumentano, ma il valore logico aumenta di 6.
  • Aggiungi uno spazio al testo della query ed esegui nuovamente: le letture non aumentano, ma il valore logico aumenta di 52 (proprio come subito dopo DBCC DROPCLEANBUFFERS).

Sembrerebbe che le 52 letture logiche conti per la generazione del piano e dei risultati, il che implica che la generazione del piano ha causato le 46 letture logiche aggiuntive. Ma le letture fisiche non risalgono di nuovo, eppure sono le stesse 52 letture logiche di quando era necessario eseguire anche le letture fisiche, quindi logical_readsnon includono quelle fisiche reads. Sto solo chiarendo questo punto, indipendentemente dal fatto che sia stato affermato o implicito nell'interrogazione.

MA, un comportamento che ho notato che viene eliminato (almeno un po ') utilizzando l'esistenza delle pagine di dati della tabella in sys.dm_os_buffer_descriptors: viene ricaricato da qualche altro processo. Se DROPCLEANBUFFERS e controlli immediatamente, allora dovrebbe essere sparito. Ma aspetta qualche minuto e si presenta di nuovo, ma questa volta senza tutte le pagine di dati. Nel mio test, la tabella ha 1 pagina IAM e 4 pagine di dati. Tutte e 5 le pagine sono nel pool di buffer dopo aver eseguito il SELECT. Ma quando viene ricaricato da qualche altro processo, è solo la pagina IAM e 1 pagina di dati. Ho pensato che potesse essere SSMS IntelliSense, ma ho rimosso tutti i riferimenti a quel nome di oggetto nella scheda della query e viene comunque ricaricato.


stranamente, ho rimosso DBCC DROPCLEANBUFFERS(e altri DBCC DROPxxxcomandi) dal mio banco di prova perché non hanno fatto alcuna differenza. L'impostazione offline del database elimina tutti i buffer e tutto il resto associato al database.
Max Vernon,

Avevo la stessa comprensione di te riguardo alle letture fisiche e le letture logiche iniziano dal pool di buffer, tra l'altro.
Max Vernon,

Ho anche provato con: DBCC FREESYSTEMCACHE ('ALL'); DBCC FREEPROCCACHE; DBCC FREESESSIONCACHE;
Max Vernon l'

1
@MaxVernon Potrebbe essere la funzione "continua a indovinare" ;-)
Solomon Rutzky,

2
@MaxVernon, non dimenticare di eseguire un CHECKPOUNTnel contesto del database prima di DBCC DROPCLEANBUFFERS.
Dan Guzman,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.