Was zeigt die Spalte "liest" in sys.dm_exec_sessions tatsächlich an?

10

Dies mag wie eine sehr grundlegende Frage erscheinen, und sollte es auch sein. Als Fan der wissenschaftlichen Methode erstelle ich jedoch gerne eine Hypothese und teste sie dann, um festzustellen, ob ich richtig bin. In diesem Fall versuche ich, die Ausgabe sys.dm_exec_sessionsund insbesondere die einzelne Spalte "liest" besser zu verstehen .

In den SQL Server-Onlinedokumenten wird dies eher trocken angegeben als:

Anzahl der Lesevorgänge, die von Anforderungen in dieser Sitzung während dieser Sitzung ausgeführt wurden. Ist nicht nullbar.

Man könnte annehmen, dass dies die Anzahl der von der Festplatte gelesenen Seiten angibt , um die von dieser Sitzung seit Beginn der Sitzung ausgegebenen Anforderungen zu erfüllen. Dies ist die Hypothese, von der ich dachte, ich würde sie testen.

Die logical_readsSpalte in derselben Tabelle ist definiert als:

Anzahl der logischen Lesevorgänge, die in der Sitzung ausgeführt wurden. Ist nicht nullbar.

Aus Erfahrung mit SQL Server glaube ich, dass diese Spalte die Anzahl der Seiten widerspiegelt, die sowohl von der Festplatte als auch im Speicher gelesen wurden . Mit anderen Worten, die Gesamtzahl der Seiten, die jemals von der Sitzung gelesen wurden, unabhängig davon, wo sich diese Seiten befinden. Das Unterscheidungsmerkmal oder Wertversprechen, zwei separate Spalten zu haben, die ähnliche Informationen bieten, scheint darin zu bestehen, dass man das Verhältnis der von disk ( reads) gelesenen Seiten zu den aus dem Puffercache ( ) gelesenen Seiten logical_readsfür eine bestimmte Sitzung verstehen kann .

Auf meinem Prüfstand habe ich eine neue Datenbank erstellt, eine einzelne Tabelle mit einer bekannten Anzahl von Datenseiten erstellt und diese Tabelle dann in einer neuen Sitzung gelesen. Dann schaute ich mir an, um sys.dm_exec_sessionszu sehen, was die Spalten readsund logical_readsüber die Sitzung sagten. An diesem Punkt bin ich durch die Ergebnisse verwirrt. Vielleicht kann mir hier jemand etwas Licht ins Dunkel bringen.

Der Prüfstand:

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;

Die erste Select-Anweisung oben zeigt, dass die Tabelle tatsächlich aus 10.000 Zeilen mit insgesamt 5.025 Seiten, 5.020 verwendeten Seiten und 5.000 Datenseiten besteht. genau wie man es erwarten würde:

Geben Sie hier die Bildbeschreibung ein

Die zweite select-Anweisung bestätigt, dass für die TestReadsTabelle nichts im Speicher ist .

In einer neuen Sitzung führen wir die folgende Abfrage durch, wobei wir die session_id notieren:

USE TestReads;

SET STATISTICS IO ON;

SELECT *
FROM dbo.TestReads;

Wie zu erwarten, liest dies die gesamte Tabelle von der Festplatte in den Speicher, wie in der Ausgabe von gezeigt 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 einer dritten Sitzung prüfen wir 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 */

Ich würde erwarten , um zu sehen , sys.dm_exec_sessionszeigen mindestens 5.000 für beide readsund logical_reads. Leider sehe ich readszeigt Null. logical_readszeigt eine erwartete Anzahl von Lesevorgängen irgendwo nördlich von 5.000 - es zeigt 5.020 in meinem Test:

Geben Sie hier die Bildbeschreibung ein

Ich weiß, dass SQL Server die gesamte TestReadsTabelle aufgrund der sys_dm_os_buffer_descriptorsDMV in den Speicher eingelesen hat :

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;

Geben Sie hier die Bildbeschreibung ein

Was mache ich falsch?

Ich verwende SQL Server 2012 11.0.5343 für diesen Test.


Weitere Ergebnisse:

Wenn ich Folgendes ausführe:

SELECT des.session_id
    , des.reads
    , des.logical_reads
FROM sys.dm_exec_sessions des

Ich sehe reads784 in der Sitzung, in der ich den Prüfstand erstelle. Alle anderen Sitzungen zeigen jedoch Null in der readsSpalte.

Ich habe jetzt meine SQL Server-Testinstanz auf 11.0.6020 aktualisiert. Das Ergebnis ist jedoch das gleiche.

Max Vernon
quelle
sys.dm_exec_requestsSie erhalten fast die gleichen set statistics io onErgebnisse.
Kin Shah
1
Interessant, SET STATISTICS IO ONkurz bevor ich in der 2. Sitzung aus der Tabelle lese, werden 3 physische Lesevorgänge und 4998 Vorlesevorgänge gemeldet. sys.dm_exec_sessionsspiegelt dies jedoch immer noch nicht in der readsSpalte wider .
Max Vernon
2
2012 sehe ich häufig 0 sowohl für Lesevorgänge als auch für logische Lesevorgänge, obwohl die Ergebnisse von STATISTICS IO i.stack.imgur.com/XbHae.png
Martin Smith
1
Tatsächlich sehe ich beide Spalten mit meinem Ansatz für alle Editionen, die ich von 2008 bis SQL2016CTP3 getestet habe
Martin Smith
1
@ MartinSmith und Max: Ich habe auch eine Verzögerung in einigen Inkrementen der readsFelder gesehen. Ich vermute, es funktioniert ähnlich wie die session_space_usage oder eine beliebige DMV, die die Tempdb-Nutzung pro Sitzung anzeigt und erst nach Abschluss der "Anfrage" erhöht wird.
Solomon Rutzky

Antworten:

2

Mein Verständnis war immer, dass readses nur physisch ist (dh von der Festplatte) und logical_readsnur aus dem Pufferpool (dh vom Speicher). Ich habe einen Schnelltest mit einer kleineren Tabelle durchgeführt, die nur 2 Datenseiten und insgesamt 3 Seiten enthält, und was ich sehe, scheint diese beiden Definitionen zu bestätigen.

Eine Sache, die wahrscheinlich zu schlechten Ergebnissen führt, ist, dass Sie den Speicher nicht löschen. Sie sollten zwischen den Tests Folgendes ausführen, um das Neuladen von der Festplatte zu erzwingen:

DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS;

Mein Testaufbau war nur der folgende:

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

Ich habe dann folgendes ausgeführt:

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

(Ja, ich habe in derselben Sitzung getestet, in der ich die DMV ausgeführt habe, aber das hat die Ergebnisse für das readsFeld nicht verzerrt und war, wenn nichts anderes, zumindest konsistent, wenn es zum logical_readsFeld beigetragen hat .)

Zum Testen würde ich den DBCC-Befehl und dann die beiden SELECT-Abfragen ausführen. Dann würde ich einen Sprung in den Feldern readsund sehen logical_reads. Ich würde die SELECT-Abfragen erneut ausführen und manchmal würde ich einen zusätzlichen Sprung sehen reads.

Danach habe ich die beiden SELECT-Abfragen viele Male ausgeführt und die readssind gleich geblieben, während die Abfragen logical_readsjedes Mal um 4 gestiegen sind.

Ich würde dann mit dem Ausführen des DBCC von vorne beginnen und das gleiche Muster sehen. Ich habe das einige Male gemacht und die angegebenen Zahlen waren über alle Testläufe hinweg konsistent.


Mehr Info:

Ich teste auch auf SQL Server 2012, SP2 - 64 Bit (11.0.5343).

Die folgenden DBCC-Befehle haben wir beide ausprobiert und keine Wirkung gesehen:

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

Die meiste Zeit DBCC DROPCLEANBUFFERSfunktioniert, aber ich sehe gelegentlich, dass es sich noch im Pufferpool befindet. Seltsam.

Wenn ich:

  • DBCC DROPCLEANBUFFERS: Die Lesevorgänge steigen um 24 und die logischen_Lesungen um 52.
  • Führen Sie SELECT [Col1] FROM dbo.ReadTest;wieder: Der liest nicht gehen, aber logical_reads steigen um 6.
  • Fügen Sie dem Abfragetext ein Leerzeichen hinzu und führen Sie es erneut aus: Die Lesevorgänge werden nicht erhöht, aber die logischen_Lesungen werden um 52 erhöht (genau wie direkt nach dem DBCC DROPCLEANBUFFERS).

Es scheint, dass die 52 logischen Lesevorgänge die Plangenerierung und die Ergebnisse berücksichtigen, was impliziert, dass die Plangenerierung die zusätzlichen 46 logischen Lesevorgänge verursacht hat. Aber die physischen Lesevorgänge steigen nicht wieder an, und dennoch sind es die gleichen 52 logischen Lesevorgänge wie damals, als auch die physischen Lesevorgänge durchgeführt werden mussten, daher logical_readssind die physischen Lesevorgänge nicht enthalten reads. Ich mache nur klar, ob es in der Frage angegeben oder impliziert wurde oder nicht.

ABER ein Verhalten, das mir aufgefallen ist und das (zumindest ein wenig) durch das Vorhandensein der Datenseiten der Tabelle in sys.dm_os_buffer_descriptorsausgelöst wird: Es wird durch einen anderen Prozess neu geladen. Wenn Sie DROPCLEANBUFFERS und sofort überprüfen, dann sollte es weg sein. Aber warten Sie ein paar Minuten und es wird wieder angezeigt, diesmal jedoch ohne alle Datenseiten. In meinem Test enthält die Tabelle 1 IAM-Seite und 4 Datenseiten. Alle 5 Seiten befinden sich nach dem Ausführen im Pufferpool SELECT. Wenn es jedoch durch einen anderen Prozess neu geladen wird, ist es nur die IAM-Seite und 1 Datenseite. Ich dachte, es könnte SSMS IntelliSense sein, aber ich habe alle Verweise auf diesen Objektnamen auf meiner Registerkarte "Abfrage" entfernt und es wird immer noch neu geladen.

Solomon Rutzky
quelle
Lustigerweise entfernte ich die DBCC DROPCLEANBUFFERS(und andere DBCC DROPxxxBefehle) von meinem Prüfstand, weil sie keinen Unterschied machten. Wenn Sie die Datenbank offline setzen, werden alle Puffer und alle anderen mit der Datenbank verbundenen Elemente gelöscht.
Max Vernon
Ich hatte das gleiche Verständnis wie Sie, dass Lesevorgänge physisch sind, und logische Lesevorgänge beginnen übrigens aus dem Pufferpool.
Max Vernon
Ich habe es auch versucht mit: DBCC FREESYSTEMCACHE ('ALL'); DBCC FREEPROCCACHE; DBCC FREESESSIONCACHE;
Max Vernon
1
@ MaxVernon Könnte die "Keep 'em Guessin" -Funktion sein ;-)
Solomon Rutzky
2
@MaxVernon, vergessen Sie nicht, eine CHECKPOUNTim Datenbankkontext vorher auszuführen DBCC DROPCLEANBUFFERS.
Dan Guzman