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_sessions
und 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_reads
Spalte 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_reads
fü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_sessions
zu sehen, was die Spalten reads
und 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:
Die zweite select-Anweisung bestätigt, dass für die TestReads
Tabelle 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_sessions
zeigen mindestens 5.000 für beide reads
und logical_reads
. Leider sehe ich reads
zeigt Null. logical_reads
zeigt eine erwartete Anzahl von Lesevorgängen irgendwo nördlich von 5.000 - es zeigt 5.020 in meinem Test:
Ich weiß, dass SQL Server die gesamte TestReads
Tabelle aufgrund der sys_dm_os_buffer_descriptors
DMV 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;
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 reads
784 in der Sitzung, in der ich den Prüfstand erstelle. Alle anderen Sitzungen zeigen jedoch Null in der reads
Spalte.
Ich habe jetzt meine SQL Server-Testinstanz auf 11.0.6020 aktualisiert. Das Ergebnis ist jedoch das gleiche.
quelle
sys.dm_exec_requests
Sie erhalten fast die gleichenset statistics io on
Ergebnisse.SET STATISTICS IO ON
kurz bevor ich in der 2. Sitzung aus der Tabelle lese, werden 3 physische Lesevorgänge und 4998 Vorlesevorgänge gemeldet.sys.dm_exec_sessions
spiegelt dies jedoch immer noch nicht in derreads
Spalte wider .STATISTICS IO
i.stack.imgur.com/XbHae.pngreads
Felder 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.Antworten:
Mein Verständnis war immer, dass
reads
es nur physisch ist (dh von der Festplatte) undlogical_reads
nur 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:
Mein Testaufbau war nur der folgende:
Ich habe dann folgendes ausgeführt:
(Ja, ich habe in derselben Sitzung getestet, in der ich die DMV ausgeführt habe, aber das hat die Ergebnisse für das
reads
Feld nicht verzerrt und war, wenn nichts anderes, zumindest konsistent, wenn es zumlogical_reads
Feld 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
reads
und sehenlogical_reads
. Ich würde die SELECT-Abfragen erneut ausführen und manchmal würde ich einen zusätzlichen Sprung sehenreads
.Danach habe ich die beiden SELECT-Abfragen viele Male ausgeführt und die
reads
sind gleich geblieben, während die Abfragenlogical_reads
jedes 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:
Die meiste Zeit
DBCC DROPCLEANBUFFERS
funktioniert, 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.SELECT [Col1] FROM dbo.ReadTest;
wieder: Der liest nicht gehen, aber logical_reads steigen um 6.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_reads
sind die physischen Lesevorgänge nicht enthaltenreads
. 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_descriptors
ausgelö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 PufferpoolSELECT
. 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.quelle
DBCC DROPCLEANBUFFERS
(und andereDBCC DROPxxx
Befehle) 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.DBCC FREESYSTEMCACHE ('ALL'); DBCC FREEPROCCACHE; DBCC FREESESSIONCACHE;
CHECKPOUNT
im Datenbankkontext vorher auszuführenDBCC DROPCLEANBUFFERS
.