To może wydawać się bardzo podstawowym pytaniem i tak powinno być. Jednak jako fan metody naukowej lubię tworzyć hipotezę, a następnie przetestować ją, aby sprawdzić, czy mam rację. W tym przypadku staram się lepiej zrozumieć wynik sys.dm_exec_sessions
, a dokładniej, pojedyncza kolumna „czyta”.
SQL Server Books Online raczej sucho określa to jako:
Liczba odczytów wykonanych według żądań w tej sesji podczas tej sesji. Nie ma wartości zerowej.
Można przypuszczać, że wskazywałoby to liczbę stron odczytanych z dysku w celu zaspokojenia żądań wydanych przez tę sesję od początku sesji. To jest hipoteza, którą pomyślałem, że przetestuję.
logical_reads
Kolumny w tej samej tabeli, jest zdefiniowana jako:
Liczba logicznych odczytów, które zostały wykonane w sesji. Nie ma wartości zerowej.
Z doświadczenia w korzystaniu z SQL Server uważam, że ta kolumna odzwierciedla liczbę stron, które zostały odczytane zarówno z dysku, jak iz pamięci . Innymi słowy, łączna liczba stron kiedykolwiek przeczytanych przez sesję, bez względu na to, gdzie te strony się znajdują. Różnicujący, czyli propozycja wartości, posiadający dwie oddzielne kolumny, które oferują podobne informacje, wydaje się, że można zrozumieć stosunek stron odczytanych z dysku ( reads
) do stron odczytanych z bufora pamięci podręcznej ( logical_reads
) dla konkretnej sesji.
Na moim stanowisku testowym utworzyłem nową bazę danych, utworzyłem pojedynczą tabelę ze znaną liczbą stron danych, a następnie odczytałem tę tabelę w nowej sesji. Potem spojrzałem, sys.dm_exec_sessions
żeby zobaczyć, co reads
i logical_reads
kolumny mówią o sesji. W tym momencie jestem zaskoczony wynikami. Być może ktoś tutaj może mi to wyjaśnić.
Stanowisko testowe:
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;
Pierwsze oświadczenie select powyżej pokazuje, że w rzeczywistości tabela składa się z 10 000 wierszy, z 5025 stron łącznie, 5020 stron używanych i 5000 stron danych; dokładnie tak, jak można się spodziewać:
Druga instrukcja select potwierdza, że nie mamy nic w pamięci dla TestReads
tabeli.
W nowej sesji wykonujemy następujące zapytanie, zwracając uwagę na id_sesji:
USE TestReads;
SET STATISTICS IO ON;
SELECT *
FROM dbo.TestReads;
Jak można się spodziewać, odczytuje całą tabelę z dysku do pamięci, jak pokazano w danych wyjściowych z 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.
W trzeciej sesji sprawdzamy 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 */
Spodziewam się zobaczyć sys.dm_exec_sessions
pokaz co najmniej 5,000 dla obu reads
i logical_reads
. Niestety, widzę reads
pokazuje zero. logical_reads
pokazuje oczekiwaną liczbę odczytów gdzieś na północ od 5000 - pokazuje 5020 w moim teście:
Wiem, że SQL Server odczytuje całą TestReads
tabelę do pamięci, dzięki 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;
Co ja robię źle?
Używam SQL Server 2012 11.0.5343 do tego testu.
Dalsze ustalenia:
Jeśli uruchomię następujące:
SELECT des.session_id
, des.reads
, des.logical_reads
FROM sys.dm_exec_sessions des
Widzę reads
784 w sesji, w której tworzę platformę testową; jednak wszystkie pozostałe sesje pokazują zero w reads
kolumnie.
Zaktualizowałem teraz moją instancję testową SQL Server do wersji 11.0.6020; jednak wynik jest taki sam.
SET STATISTICS IO ON
zanim przeczytałem ze stołu w drugiej sesji raporty 3 fizycznych odczytów i 4998 odczytów z wyprzedzeniem; jednak sys.dm_exec_sessions
nadal nie odzwierciedla tego w reads
kolumnie.
STATISTICS IO
i.stack.imgur.com/XbHae.png
reads
pól. Podejrzewam, że działa podobnie jak sesja_przestrzeni_sesji lub jakikolwiek DMV, który pokazuje użycie tempdb na sesję, która nie rośnie, dopóki „żądanie” nie zakończy się.
sys.dm_exec_requests
da ci prawie to samo coset statistics io on
wyniki.