Це може здатися дуже базовим питанням, і справді воно повинно бути. Однак, як шанувальник наукового методу, я люблю створювати гіпотезу, а потім перевірити її, щоб перевірити, чи я прав. У цьому випадку я намагаюся краще зрозуміти результат sys.dm_exec_sessions
, а точніше, єдиний стовпець "читається".
SQL Server Books Online досить суворо визначає це як:
Кількість прочитаних запитів за запитами на цій сесії протягом цієї сесії. Не є нульовим.
Можна припустити, що це вказуватиме кількість сторінок, прочитаних з диска, щоб задовольнити запити, видані цим сеансом з початку сеансу. Це гіпотеза, яку я думав перевірити.
logical_reads
Стовпець в тій же таблиці, визначається як:
Кількість логічних читань, які були виконані на сеансі. Не є нульовим.
З досвіду використання SQL Server, я вважаю, що цей стовпець відображає кількість сторінок, прочитаних як з диска, так і з пам'яті . Іншими словами, загальна кількість сторінок, які коли-небудь читав сеанс, незалежно від того, де вони перебувають. Диференціатор або пропозиція значення, що має два окремі стовпці, які пропонують подібну інформацію, здається, що можна зрозуміти співвідношення сторінок, прочитаних з диска ( reads
), і тих, які читаються з кеш-пам'яті буфера ( logical_reads
) для конкретного сеансу.
На своїй тестовій установці я створив нову базу даних, створив єдину таблицю з відомою кількістю сторінок даних, а потім прочитав цю таблицю в новому сеансі. Потім я подивився на , sys.dm_exec_sessions
щоб побачити , що reads
і logical_reads
стовпці говорилося про сесії. На даний момент я збентежений результатами. Можливо, хтось тут може пролити трохи світла на це на мене.
Випробувальна установка:
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;
Перше твердження про вибір вище показує, що насправді таблиця складається з 10 000 рядків із загальною кількістю 5025 сторінок, 5,020 сторінок, що використовуються, та 5000 сторінок даних; саме так, як можна було б очікувати:
Другий оператор select підтверджує, що ми не маємо нічого в пам'яті для TestReads
таблиці.
У новому сеансі ми робимо наступний запит, беручи до уваги session_id:
USE TestReads;
SET STATISTICS IO ON;
SELECT *
FROM dbo.TestReads;
Як і слід було очікувати, це зчитує всю таблицю з диска в пам'ять, як показано у висновку з 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.
На третій сесії ми перевіряємо 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 */
Я очікував би побачити sys.dm_exec_sessions
шоу принаймні 5000 для обох reads
та logical_reads
. На жаль, я бачу, reads
показує нуль. logical_reads
показує очікувану кількість прочитаних десь на північ від 5000 - це показує 5,020 у моєму тесті:
Я знаю, що SQL Server читав всю TestReads
таблицю в пам'ять завдяки 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;
Що я роблю неправильно?
Я використовую SQL Server 2012 11.0.5343 для цього тесту.
Подальші результати:
Якщо я запускаю наступне:
SELECT des.session_id
, des.reads
, des.logical_reads
FROM sys.dm_exec_sessions des
Я бачу reads
784 на сеансі, де я створюю тестову установку; однак усі інші сеанси показують нуль у reads
стовпці.
Зараз я оновив тестовий екземпляр SQL Server до 11.0.6020; однак результат той самий.
SET STATISTICS IO ON
якраз перед тим, як я прочитав із таблиці в 2-му сеансі звіти про 3 фізичні читання, а 4998 - заздалегідь прочитані; однак це sys.dm_exec_sessions
все ще не відображає це в reads
стовпці.
STATISTICS IO
i.stack.imgur.com/XbHae.png
reads
полів. Я підозрюю, що він працює так само, як session_space_usage або будь-який інший DMV, який показує використання tempdb за сеанс, який не збільшується, поки "запит" не завершиться.
sys.dm_exec_requests
дасть вам майже те саме, що іset statistics io on
результати.