¿Qué indica realmente la columna "lecturas" en sys.dm_exec_sessions?


10

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_readscolumna 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_sessionspara ver qué decían las columnas readsy logical_readssobre 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:

ingrese la descripción de la imagen aquí

La segunda instrucción select confirma que no tenemos nada en memoria para la TestReadstabla.

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_sessionsmostrar al menos 5,000 para ambos readsy logical_reads. Por desgracia, veo readsmuestra cero. logical_readsmuestra un número esperado de lecturas en algún lugar al norte de 5,000; muestra 5,020 en mi prueba:

ingrese la descripción de la imagen aquí

Sé que SQL Server leyó toda la TestReadstabla en la memoria, en virtud del sys_dm_os_buffer_descriptorsDMV:

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;

ingrese la descripción de la imagen aquí

¿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 reads784 en la sesión donde estoy creando la plataforma de prueba; sin embargo, todas las demás sesiones muestran cero en la readscolumna.

Ahora he actualizado mi instancia de prueba de SQL Server a 11.0.6020; Sin embargo, el resultado es el mismo.


sys.dm_exec_requestste dará casi lo mismo que los set statistics io onresultados.
Kin Shah

1
Interesante, SET STATISTICS IO ONjusto 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_sessionstodavía no refleja eso en la readscolumna.
Max Vernon

2
En 2012, con frecuencia veo 0 para las lecturas y las lecturas lógicas a pesar de los resultados distintos de cero informados por STATISTICS IO i.stack.imgur.com/XbHae.png
Martin Smith

1
En realidad, veo ambas columnas cero con mi enfoque en todas las ediciones que he probado desde 2008 hasta SQL2016CTP3
Martin Smith

1
@ MartininSmith y Max: También he visto un retraso en algunos de los incrementos de los readscampos. 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".
Solomon Rutzky

Respuestas:


2

Mi comprensión siempre ha sido que readssolo es física (es decir, desde el disco) y logical_readses solo del grupo de búferes (es decir, de la memoria). Hice una prueba rápida con una tabla más pequeña que solo tiene 2 páginas de datos y 3 páginas en total, y lo que veo parece confirmar esas dos definiciones.

Una cosa que probablemente le está dando malos resultados es que no está limpiando la memoria. Debe ejecutar lo siguiente entre pruebas para forzarlo a recargarse desde el disco:

DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS;

Mi configuración de prueba fue solo la siguiente:

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

Luego ejecuté lo siguiente:

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

(Sí, estaba probando en la misma sesión en la que estaba ejecutando el DMV, pero eso no sesgó los resultados para el readscampo, y si nada más, fue al menos consistente si contribuyó al logical_readscampo).

Para probar, ejecutaría el comando DBCC y luego las dos consultas SELECT. Entonces vería un salto en los campos readsy logical_reads. Volvería a ejecutar las consultas SELECT y, a veces, vería un salto adicional reads.

Después de eso, ejecutaba las dos consultas SELECT muchas veces y seguía readssiendo la misma, mientras que logical_readsaumentaba en 4 cada vez.

Entonces comenzaría de nuevo ejecutando el DBCC y vería el mismo patrón. Lo hice varias veces y los números informados fueron consistentes en todas las ejecuciones de prueba.


Más información:

También estoy probando en SQL Server 2012, SP2 - 64 bits (11.0.5343).

Los siguientes comandos DBCC hemos intentado y no hemos visto ningún efecto:

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

La mayoría de las veces DBCC DROPCLEANBUFFERSfunciona, pero ocasionalmente veo que todavía está en el Buffer Pool. Impar.

Cuando yo:

  • DBCC DROPCLEANBUFFERS: Las lecturas aumentan en 24 y logical_reads aumentan en 52.
  • Ejecutar de SELECT [Col1] FROM dbo.ReadTest;nuevo: las lecturas no aumentan, pero los hilos lógicos aumentan en 6.
  • Agregue un espacio al texto de la consulta y vuelva a ejecutarlo: las lecturas no aumentan, pero los hilos lógicos aumentan en 52 (justo después de DBCC DROPCLEANBUFFERS).

Parece que las 52 lecturas lógicas explican la generación del plan y los resultados, lo que implica que la generación del plan causó las 46 lecturas lógicas adicionales. Pero las lecturas físicas no vuelven a subir y, sin embargo, son las mismas 52 lecturas lógicas que cuando necesitaba hacer también las lecturas físicas, por logical_readslo tanto , no incluye las físicas reads. Solo estoy aclarando este punto, ya sea que se haya declarado o implícito en la Pregunta.

PERO, un comportamiento que noté que se deshace (al menos un poco) usando la existencia de las páginas de datos de la tabla en sys.dm_os_buffer_descriptors: otro proceso lo vuelve a cargar. Si DROPCLEANBUFFERS y comprueba de inmediato, entonces debería desaparecer. Pero espere unos minutos y aparecerá de nuevo, pero esta vez sin todas las páginas de datos. En mi prueba, la tabla tiene 1 página IAM y 4 páginas de datos. Las 5 páginas están en el grupo de búferes después de hacer el SELECT. Pero cuando algún otro proceso lo vuelve a cargar, es solo la página IAM y 1 página de datos. Pensé que podría ser SSMS IntelliSense, pero eliminé todas las referencias a ese nombre de objeto en mi pestaña de consulta y todavía se vuelve a cargar.


Curiosamente, eliminé el DBCC DROPCLEANBUFFERS(y otros DBCC DROPxxxcomandos) de mi plataforma de prueba porque no hicieron ninguna diferencia. Establecer la base de datos fuera de línea elimina todos los búferes y todo lo demás asociado con la base de datos.
Max Vernon

Tenía el mismo entendimiento que usted acerca de que las lecturas son físicas, y las lecturas lógicas comienzan desde el grupo de búferes, por cierto.
Max Vernon

También lo probé con: DBCC FREESYSTEMCACHE ('ALL'); DBCC FREEPROCCACHE; DBCC FREESESSIONCACHE;
Max Vernon

1
@MaxVernon podría ser la función "mantenerlos adivinando" ;-)
Solomon Rutzky

2
@MaxVernon, no olvides ejecutar un CHECKPOUNTen el contexto de la base de datos antes DBCC DROPCLEANBUFFERS.
Dan Guzman
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.