Apa yang sebenarnya ditunjukkan oleh kolom “dibaca” di sys.dm_exec_sessions?


10

Ini mungkin tampak seperti pertanyaan yang sangat mendasar, dan memang seharusnya begitu. Namun, sebagai penggemar metode ilmiah, saya suka membuat hipotesis, kemudian mengujinya untuk melihat apakah saya benar. Dalam hal ini, saya mencoba untuk lebih memahami output sys.dm_exec_sessions, dan lebih khusus, kolom tunggal "berbunyi".

SQL Server Books Online agak kering menetapkan ini sebagai:

Jumlah pembacaan yang dilakukan, berdasarkan permintaan dalam sesi ini, selama sesi ini. Tidak dapat dibatalkan.

Orang mungkin menganggap ini akan menunjukkan jumlah halaman yang dibaca dari disk untuk memenuhi permintaan yang dikeluarkan oleh sesi ini sejak awal sesi. Ini adalah hipotesis yang saya pikir akan saya uji.

The logical_readskolom di meja yang sama didefinisikan sebagai:

Jumlah pembacaan logis yang telah dilakukan pada sesi. Tidak dapat dibatalkan.

Dari pengalaman menggunakan SQL Server, saya percaya kolom ini mencerminkan jumlah halaman yang telah dibaca baik dari disk maupun di memori . Dengan kata lain, jumlah total halaman yang pernah dibaca oleh sesi, di mana pun halaman itu berada. Pembeda, atau nilai-proposisi, memiliki dua kolom terpisah yang menawarkan informasi serupa tampaknya adalah bahwa seseorang dapat memahami rasio halaman yang dibaca dari disk ( reads) vs yang dibaca dari cache buffer ( logical_reads) untuk sesi tertentu.

Di rig pengujian saya, saya telah membuat database baru, membuat tabel tunggal dengan jumlah halaman data yang diketahui, kemudian membaca tabel itu dalam sesi baru. Kemudian saya melihat sys.dm_exec_sessionsuntuk melihat apa yang dikatakan kolom readsdan logical_readstentang sesi. Pada titik ini saya bingung dengan hasilnya. Mungkin seseorang di sini dapat menjelaskan tentang hal ini untuk saya.

Rig uji:

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;

Pernyataan pilih pertama di atas menunjukkan bahwa sebenarnya tabel tersebut terdiri dari 10.000 baris, dengan 5.025 halaman total, 5.020 halaman yang digunakan, dan 5.000 halaman data; persis seperti yang diharapkan:

masukkan deskripsi gambar di sini

Pernyataan pilih kedua mengonfirmasi bahwa kami tidak memiliki apa pun di TestReadstabel untuk memori .

Dalam sesi baru , kami melakukan kueri berikut, mencatat session_id:

USE TestReads;

SET STATISTICS IO ON;

SELECT *
FROM dbo.TestReads;

Seperti yang diharapkan, ini membaca seluruh tabel dari disk ke memori, seperti yang ditunjukkan pada output dari 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.

Dalam sesi ketiga , kami memeriksa 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 */

Saya berharap untuk melihat sys.dm_exec_sessionspertunjukan setidaknya 5.000 untuk keduanya readsdan logical_reads. Sayangnya, saya melihat readsmenunjukkan nol. logical_readstidak menunjukkan jumlah pembacaan yang diharapkan di suatu tempat di utara 5.000 - ini menunjukkan 5.020 dalam pengujian saya:

masukkan deskripsi gambar di sini

Saya tahu SQL Server membaca seluruh TestReadstabel ke dalam memori, berdasarkan 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;

masukkan deskripsi gambar di sini

Apa yang saya lakukan salah?

Saya menggunakan SQL Server 2012 11.0.5343 untuk tes ini.


Temuan lebih lanjut:

Jika saya menjalankan yang berikut ini:

SELECT des.session_id
    , des.reads
    , des.logical_reads
FROM sys.dm_exec_sessions des

Saya melihat reads784 di sesi di mana saya membuat rig uji; namun semua sesi lainnya menunjukkan nol pada readskolom.

Saya sekarang telah memperbarui contoh pengujian SQL Server saya ke 11.0.6020; Namun hasilnya sama.


sys.dm_exec_requestsakan memberi Anda set statistics io onhasil yang hampir sama .
Kin Shah

1
Menarik SET STATISTICS IO ONsebelum saya membaca dari tabel pada sesi ke-2 melaporkan 3 membaca fisik, dan 4998 membaca-baca selanjutnya; Namun sys.dm_exec_sessionsmasih tidak mencerminkan hal itu di readskolom.
Max Vernon

2
Pada 2012 saya sering melihat 0 untuk bacaan dan bacaan logis meskipun hasil tidak nol dilaporkan dari STATISTICS IO i.stack.imgur.com/XbHae.png
Martin Smith

1
Sebenarnya saya melihat kedua kolom nol dengan pendekatan saya pada semua edisi yang telah saya uji dari 2008 ke SQL2016CTP3
Martin Smith

1
@ MartinSmith dan Max: Saya juga telah melihat penundaan dalam beberapa peningkatan readsbidang. Saya menduga ini berfungsi seperti session_space_usage atau DMV apa pun yang menunjukkan penggunaan tempdb per sesi yang tidak bertambah hingga "permintaan" selesai.
Solomon Rutzky

Jawaban:


2

Pemahaman saya selalu bahwa readsitu hanya fisik (yaitu dari disk) dan logical_readshanya dari Buffer Pool (yaitu dari memori). Saya melakukan tes cepat dengan tabel yang lebih kecil yang hanya memiliki 2 halaman data dan total 3 halaman, dan apa yang saya lihat tampaknya mengkonfirmasi kedua definisi tersebut.

Satu hal yang mungkin memberi Anda hasil buruk adalah bahwa Anda tidak membersihkan memori. Anda harus menjalankan yang berikut di antara tes untuk memaksanya memuat ulang dari disk:

DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS;

Pengaturan pengujian saya hanya sebagai berikut:

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

Saya kemudian menjalankan yang berikut:

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

(Ya, saya menguji dalam sesi yang sama dengan saya menjalankan DMV, tetapi itu tidak condongkan hasil untuk readsbidang tersebut, dan jika tidak ada yang lain, setidaknya konsisten jika memberikan kontribusi ke logical_readsbidang.)

Untuk pengujian saya akan menjalankan perintah DBCC dan kemudian dua query SELECT. Lalu saya akan melihat lompatan di kedua bidang readsdan logical_reads. Saya akan menjalankan kueri SELECT lagi dan kadang-kadang saya melihat lompatan tambahan reads.

Setelah itu, saya akan menjalankan dua query SELECT berkali-kali dan readsakan tetap sama sementara logical_readsnaik oleh 4 setiap kali.

Saya kemudian akan mulai dengan menjalankan DBCC dan melihat pola yang sama. Saya melakukan ini beberapa kali dan angka yang dilaporkan konsisten di semua uji coba.


Info lebih lanjut:

Saya juga menguji pada SQL Server 2012, SP2 - 64 bit (11.0.5343).

Perintah DBCC berikut ini telah kami coba dan lihat tidak berpengaruh:

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

Sebagian besar waktu DBCC DROPCLEANBUFFERSmemang berhasil, tetapi kadang-kadang saya melihat bahwa itu masih di Buffer Pool. Aneh.

Ketika saya:

  • DBCC DROPCLEANBUFFERS: Bacaan naik 24 dan logical_reads naik 52.
  • Jalankan SELECT [Col1] FROM dbo.ReadTest;lagi: Pembacaan tidak naik, tetapi logical_reads naik 6.
  • Tambahkan spasi ke teks kueri dan jalankan kembali: Bacaan tidak naik, tetapi logical_reads naik sebesar 52 (sama seperti setelah itu DBCC DROPCLEANBUFFERS).

Akan terlihat bahwa 52 pembacaan logis memperhitungkan pembuatan rencana dan hasilnya, yang menyiratkan bahwa pembuatan rencana menyebabkan 46 pembacaan logis tambahan. Tetapi pembacaan fisik tidak naik lagi, namun itu adalah pembacaan logis yang sama seperti ketika pembacaan fisik juga perlu, maka pembacaan fisik logical_readstidak termasuk fisik reads. Saya hanya memperjelas poin ini, apakah itu dinyatakan atau tersirat dalam Pertanyaan.

NAMUN, satu perilaku yang saya perhatikan yang melempar (setidaknya sedikit) menggunakan keberadaan halaman data tabel di sys.dm_os_buffer_descriptors: itu akan dimuat ulang oleh beberapa proses lainnya. Jika Anda DROPCLEANBUFFERS dan segera memeriksa, maka itu harus pergi. Tapi tunggu beberapa menit dan itu muncul lagi, tapi kali ini tanpa semua halaman data. Dalam pengujian saya, tabel memiliki 1 halaman IAM dan 4 halaman data. Semua 5 halaman berada di buffer pool setelah saya melakukan SELECT. Tetapi ketika itu dimuat ulang oleh beberapa proses lain, itu hanya halaman IAM dan 1 halaman data. Saya pikir itu mungkin SSMS IntelliSense, tapi saya menghapus semua referensi ke nama objek di tab kueri saya dan itu masih dimuat ulang.


cukup lucu, saya menghapus DBCC DROPCLEANBUFFERS(dan DBCC DROPxxxperintah lain ) dari rig pengujian saya karena mereka tidak membuat perbedaan. Mengatur basis data secara offline membuat semua buffer, dan segala sesuatu yang terkait dengan database
Max Vernon

Saya berada di bawah pemahaman yang sama seperti Anda tentang membaca menjadi fisik, dan membaca logis dimulai dari buffer pool, btw.
Max Vernon

Saya juga mencobanya dengan: DBCC FREESYSTEMCACHE ('ALL'); DBCC FREEPROCCACHE; DBCC FREESESSIONCACHE;
Max Vernon

1
@MaxVernon Bisa jadi fitur "keep 'em guessin" ;-)
Solomon Rutzky

2
@ MaxVernon, jangan lupa untuk mengeksekusi CHECKPOUNTdalam konteks basis data sebelumnya DBCC DROPCLEANBUFFERS.
Dan Guzman
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.