Isso pode parecer uma pergunta muito básica, e de fato deveria ser. No entanto, como fã do método científico, gosto de criar uma hipótese e testá-la para ver se estou correta. Nesse caso, estou tentando entender melhor a saída sys.dm_exec_sessions
e, mais especificamente, a única coluna "lê".
Os Manuais Online do SQL Server especificam isso secamente como:
Número de leituras realizadas, por solicitações nesta sessão, durante esta sessão. Não é anulável.
Pode-se presumir que isso indica o número de páginas lidas do disco para satisfazer as solicitações emitidas por esta sessão desde o início da sessão. Essa é a hipótese que pensei em testar.
A logical_reads
coluna nessa mesma tabela é definida como:
Número de leituras lógicas que foram executadas na sessão. Não é anulável.
Por experiência usando o SQL Server, acredito que esta coluna reflete o número de páginas que foram lidas no disco e na memória . Em outras palavras, o número total de páginas já lidas pela sessão, não importa onde essas páginas residam. O diferencial, ou proposição de valor, de ter duas colunas separadas que oferecem informações semelhantes parece ser a capacidade de entender a proporção de páginas lidas no disco ( reads
) versus as lidas no cache do buffer ( logical_reads
) para uma sessão específica.
No meu equipamento de teste, criei um novo banco de dados, criei uma única tabela com um número conhecido de páginas de dados e depois li essa tabela em uma nova sessão. Então olhei sys.dm_exec_sessions
para ver o que as colunas reads
e logical_reads
disseram sobre a sessão. Neste ponto, estou confuso com os resultados. Talvez alguém aqui possa esclarecer isso para mim.
O equipamento de teste:
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;
A primeira instrução de seleção acima mostra que, de fato, a tabela consiste em 10.000 linhas, com 5.025 páginas no total, 5.020 páginas usadas e 5.000 páginas de dados; exatamente como seria de esperar:
A segunda instrução select confirma que não temos nada na memória para a TestReads
tabela.
Em uma nova sessão , fazemos a seguinte consulta, anotando o session_id:
USE TestReads;
SET STATISTICS IO ON;
SELECT *
FROM dbo.TestReads;
Como seria de esperar, isso lê a tabela inteira do disco para a memória, conforme mostrado na saída 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.
Em uma terceira sessão, inspecionamos 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 */
Eu esperaria ver sys.dm_exec_sessions
mostrar pelo menos 5.000 para ambos reads
e logical_reads
. Infelizmente, eu vejo reads
mostra zero. logical_reads
mostra um número esperado de leituras em algum lugar ao norte de 5.000 - mostra 5.020 no meu teste:
Eu sei que o SQL Server leu a TestReads
tabela inteira na memória, em virtude da 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;
O que estou fazendo de errado?
Estou usando o SQL Server 2012 11.0.5343 para este teste.
Outras descobertas:
Se eu executar o seguinte:
SELECT des.session_id
, des.reads
, des.logical_reads
FROM sys.dm_exec_sessions des
Eu vejo o reads
784 na sessão em que estou criando o equipamento de teste; no entanto, todas as outras sessões mostram zero na reads
coluna.
Atualizei agora minha instância de teste do SQL Server para 11.0.6020; no entanto, o resultado é o mesmo.
SET STATISTICS IO ON
antes de ler a tabela da 2ª sessão relata 3 leituras físicas e 4998 leituras de leitura antecipada; no entanto, sys.dm_exec_sessions
ainda não reflete isso na reads
coluna.
STATISTICS IO
i.stack.imgur.com/XbHae.png
reads
campos. Eu suspeito que ele funciona muito como o session_space_usage ou qualquer DMV que mostre o uso do tempdb por sessão que não é incrementado até que a "solicitação" seja concluída.
sys.dm_exec_requests
lhe dará quase o mesmo que osset statistics io on
resultados.