Esto puede parecer una pregunta muy básica, y de hecho debería serlo. Sin embargo, como fanático del método científico, me gusta crear una hipótesis, luego probarla para ver si estoy en lo correcto. En este caso, estoy tratando de comprender mejor el resultado de sys.dm_exec_sessions
, y más específicamente, la columna única "lee".
Los Libros en pantalla de SQL Server especifican esto de forma bastante seca como:
Número de lecturas realizadas, por solicitudes en esta sesión, durante esta sesión. No es anulable.
Se podría suponer que esto indicaría el número de páginas leídas del disco para satisfacer las solicitudes emitidas por esta sesión desde el inicio de la sesión. Esta es la hipótesis que pensé probar.
La logical_reads
columna en esa misma tabla se define como:
Número de lecturas lógicas que se han realizado en la sesión. No es anulable.
Por experiencia con SQL Server, creo que esta columna refleja el número de páginas que se han leído tanto desde el disco como en la memoria . En otras palabras, el número total de páginas cada vez leído por la sesión, sin importar donde residen esas páginas. El diferenciador, o propuesta de valor, de tener dos columnas separadas que ofrecen información similar parece ser que uno puede entender la proporción de páginas leídas del disco ( reads
) frente a las leídas del caché del búfer ( logical_reads
) para una sesión específica.
En mi plataforma de prueba, creé una nueva base de datos, creé una sola tabla con un número conocido de páginas de datos, luego leí esa tabla en una nueva sesión. Luego miré sys.dm_exec_sessions
para ver qué decían las columnas reads
y logical_reads
sobre la sesión. En este punto estoy confundido por los resultados. Quizás alguien aquí pueda arrojarme algo de luz sobre esto.
La plataforma de prueba:
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 primera declaración de selección anterior muestra que, de hecho, la tabla consta de 10,000 filas, con 5,025 páginas en total, 5,020 páginas usadas y 5,000 páginas de datos; precisamente como cabría esperar:
La segunda instrucción select confirma que no tenemos nada en memoria para la TestReads
tabla.
En una nueva sesión , hacemos la siguiente consulta, tomando nota del session_id:
USE TestReads;
SET STATISTICS IO ON;
SELECT *
FROM dbo.TestReads;
Como era de esperar, esto lee toda la tabla del disco a la memoria, como se muestra en la salida de 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.
En una tercera sesión, inspeccionamos 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 */
Esperaría ver sys.dm_exec_sessions
mostrar al menos 5,000 para ambos reads
y logical_reads
. Por desgracia, veo reads
muestra cero. logical_reads
muestra un número esperado de lecturas en algún lugar al norte de 5,000; muestra 5,020 en mi prueba:
Sé que SQL Server leyó toda la TestReads
tabla en la memoria, en virtud del 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;
¿Qué estoy haciendo mal?
Estoy usando SQL Server 2012 11.0.5343 para esta prueba.
Otros hallazgos:
Si ejecuto lo siguiente:
SELECT des.session_id
, des.reads
, des.logical_reads
FROM sys.dm_exec_sessions des
Veo reads
784 en la sesión donde estoy creando la plataforma de prueba; sin embargo, todas las demás sesiones muestran cero en la reads
columna.
Ahora he actualizado mi instancia de prueba de SQL Server a 11.0.6020; Sin embargo, el resultado es el mismo.
SET STATISTICS IO ON
justo antes de leer de la tabla en la segunda sesión, informa 3 lecturas físicas y 4998 lecturas de lectura anticipada; sin embargo sys.dm_exec_sessions
todavía no refleja eso en la reads
columna.
STATISTICS IO
i.stack.imgur.com/XbHae.png
reads
campos. Sospecho que funciona de manera muy similar al session_space_usage o cualquier DMV que muestre el uso de tempdb por sesión que no se incrementa hasta que finaliza la "solicitud".
sys.dm_exec_requests
te dará casi lo mismo que losset statistics io on
resultados.