คอลัมน์“ อ่าน” ใน sys.dm_exec_sessions จริง ๆ บ่งชี้อะไร


10

นี่อาจดูเหมือนคำถามพื้นฐานมากและแน่นอนควรเป็นเช่นนั้น อย่างไรก็ตามในฐานะแฟนของวิธีการทางวิทยาศาสตร์ฉันชอบที่จะสร้างสมมติฐานแล้วทดสอบเพื่อดูว่าฉันถูกต้อง ในกรณีนี้ฉันพยายามทำความเข้าใจกับผลลัพธ์ของ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 แถวโดยมีหน้าทั้งหมด 5,025 หน้าใช้ 5,020 หน้าและหน้าข้อมูล 5,000 หน้า แม่นยำอย่างที่คาดหวัง:

ป้อนคำอธิบายรูปภาพที่นี่

คำสั่ง 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การแสดงอย่างน้อย 5,000 สำหรับทั้งสองและreads logical_readsอนิจจาฉันเห็นreadsศูนย์ logical_readsแสดงจำนวนที่คาดว่าจะมีผู้อ่านมากกว่า 5,000 คน - มันแสดงให้เห็น 5,020 ในการทดสอบของฉัน

ป้อนคำอธิบายรูปภาพที่นี่

ฉันรู้ว่า SQL Server อ่านทั้งTestReadsตารางลงในหน่วยความจำโดยอาศัย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;

ป้อนคำอธิบายรูปภาพที่นี่

ผมทำอะไรผิดหรือเปล่า?

ฉันใช้ 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; อย่างไรก็ตามผลลัพธ์จะเหมือนกัน


sys.dm_exec_requestsจะให้set statistics io onผลลัพธ์เกือบเหมือนกัน
Kin Shah

1
ที่น่าสนใจSET STATISTICS IO ONก่อนที่ฉันจะอ่านจากตารางในเซสชั่นที่ 2 รายงาน 3 อ่านทางกายภาพและ 4998 อ่านล่วงหน้าอ่าน; อย่างไรก็ตามsys.dm_exec_sessionsยังคงไม่ได้สะท้อนให้เห็นว่าในreadsคอลัมน์
Max Vernon

2
ในปี 2012 ฉันเห็น 0 ทั้งการอ่านและการอ่านแบบลอจิคัลบ่อยๆแม้ว่าจะไม่มีผลลัพธ์ที่เป็นศูนย์รายงานจากSTATISTICS IO i.stack.imgur.com/XbHae.png
Martin Smith

1
ที่จริงฉันเห็นทั้งสองคอลัมน์เป็นศูนย์ด้วยวิธีการของฉันในทุกรุ่นที่ฉันได้ทดสอบจาก 2008 ถึง SQL2016CTP3
Martin Smith

1
@MartinSmith และ Max: ฉันเคยเห็นความล่าช้าในการเพิ่มขึ้นของบางreadsฟิลด์ ฉันสงสัยว่ามันใช้งานได้เหมือน session_space_usage หรือ DMV ใดก็ตามที่แสดงการใช้ tempdb ต่อเซสชันที่ไม่เพิ่มขึ้นจนกว่า "คำขอ" จะเสร็จสิ้น
โซโลมอน Rutzky

คำตอบ:


2

ความเข้าใจของฉันreadsคือสิ่งที่มีอยู่จริงเท่านั้น (เช่นจากดิสก์) และlogical_readsมาจากบัฟเฟอร์พูล (เช่นจากหน่วยความจำ) เท่านั้น ฉันทำการทดสอบอย่างรวดเร็วด้วยตารางที่เล็กกว่าซึ่งมีเพียง 2 หน้าข้อมูลและทั้งหมด 3 หน้าและสิ่งที่ฉันเห็นดูเหมือนจะยืนยันคำจำกัดความทั้งสองนั้น

สิ่งหนึ่งที่อาจให้ผลลัพธ์ที่ไม่ดีคือคุณไม่ได้ล้างหน่วยความจำ คุณควรรันสิ่งต่อไปนี้ระหว่างการทดสอบเพื่อบังคับให้โหลดซ้ำจากดิสก์:

DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS;

การตั้งค่าการทดสอบของฉันเป็นเพียงสิ่งต่อไปนี้:

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

จากนั้นฉันก็วิ่งต่อไปนี้:

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

(ใช่ฉันกำลังทดสอบในเซสชั่นเดียวกับที่ฉันเรียกใช้ DMV ใน แต่นั่นก็ไม่ได้บิดเบือนผลลัพธ์สำหรับreadsฟิลด์และถ้าไม่มีอะไรอื่นอย่างน้อยก็สอดคล้องกันอย่างน้อยถ้ามันมีส่วนร่วมในlogical_readsสนาม)

สำหรับการทดสอบฉันจะเรียกใช้คำสั่ง DBCC แล้วเลือกสองแบบสอบถาม จากนั้นฉันจะเห็นการกระโดดทั้งในreadsและlogical_readsนา ฉันจะเรียกใช้คำสั่ง SELECT readsอีกครั้งและบางครั้งผมจะเห็นกระโดดเพิ่มเติมใน

หลังจากนั้นฉันจะเรียกใช้การสืบค้น SELECT สองครั้งหลายครั้งและreadsจะยังคงเหมือนเดิมในขณะที่การlogical_readsเพิ่มขึ้น 4 ครั้งทุกครั้ง

ฉันจะเริ่มต้นใหม่ด้วยการรัน DBCC และดูรูปแบบเดียวกันนั้น ฉันทำแบบนี้สองสามครั้งและตัวเลขที่รายงานนั้นสอดคล้องกันในทุกการทดสอบ


ข้อมูลเพิ่มเติม:

ฉันกำลังทดสอบ SQL Server 2012, SP2 - 64 บิต (11.0.5343)

คำสั่ง DBCC ต่อไปนี้เราได้ลองและไม่เห็นผลใด ๆ :

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

เวลาส่วนใหญ่ใช้DBCC DROPCLEANBUFFERSงานได้ แต่บางครั้งฉันเห็นว่ามันยังคงอยู่ในบัฟเฟอร์พูล แปลก

เมื่อฉัน:

  • DBCC DROPCLEANBUFFERS: การอ่านเพิ่มขึ้น 24 และ logical_reads เพิ่มขึ้น 52
  • เรียกใช้SELECT [Col1] FROM dbo.ReadTest;อีกครั้ง: การอ่านไม่ขึ้น แต่ลอจิกเพิ่มขึ้น 6
  • เพิ่มช่องว่างให้กับข้อความค้นหาและเรียกใช้อีกครั้ง: การอ่านไม่ขึ้น แต่ลอจิกเพิ่มขึ้น 52 (เหมือนหลังDBCC DROPCLEANBUFFERS)

มันจะปรากฏว่าตรรกะ 52 อ่านบัญชีสำหรับการสร้างแผนและผลซึ่งหมายความว่าการสร้างแผนทำให้เกิด 46 อ่านตรรกะเพิ่มเติม แต่ทางกายภาพอ่านไม่ขึ้นไปอีกครั้งและมันยังเป็นเหมือนกัน 52 ตรรกะอ่านเหมือนเดิมเมื่อมันไม่จำเป็นที่จะต้องทำกายภาพอ่านจึงไม่รวมทางกายภาพlogical_reads readsฉันแค่ทำให้ประเด็นนี้ชัดเจนไม่ว่าจะมีการระบุหรือบอกเป็นนัยในคำถาม

แต่พฤติกรรมอย่างหนึ่งที่ฉันสังเกตเห็นได้คือการปิด (อย่างน้อยนิด) โดยใช้การมีอยู่ของหน้าข้อมูลในตารางsys.dm_os_buffer_descriptors: มันได้รับการโหลดใหม่โดยกระบวนการอื่น หากคุณ DROPCLEANBUFFERS และตรวจสอบทันทีมันควรจะหายไป แต่รอสักครู่แล้วมันจะปรากฏขึ้นอีกครั้ง แต่คราวนี้ไม่มีหน้าข้อมูลทั้งหมด ในการทดสอบของฉันตารางมี 1 หน้า IAM และ 4 หน้าข้อมูล ทั้งหมด 5 SELECTหน้าอยู่ในสระว่ายน้ำบัฟเฟอร์หลังจากที่ผมทำ แต่เมื่อมันถูกโหลดใหม่โดยกระบวนการอื่นมันเป็นเพียงหน้า IAM และ 1 หน้าข้อมูล ฉันคิดว่าอาจเป็น SSMS IntelliSense แต่ฉันลบการอ้างอิงทั้งหมดไปยังชื่อวัตถุนั้นในแท็บแบบสอบถามของฉันและยังคงได้รับการโหลดใหม่


สนุกพอฉันลบDBCC DROPCLEANBUFFERS(และDBCC DROPxxxคำสั่งอื่น ๆ) ออกจากอุปกรณ์ทดสอบเพราะพวกเขาไม่ได้สร้างความแตกต่าง การตั้งค่าฐานข้อมูลออฟไลน์จะลดบัฟเฟอร์ทั้งหมดและทุกอย่างที่เกี่ยวข้องกับฐานข้อมูล
Max Vernon

ฉันอยู่ภายใต้ความเข้าใจเช่นเดียวกับคุณเกี่ยวกับการอ่านที่มีอยู่จริงและการอ่านเชิงตรรกะเริ่มต้นจากบัฟเฟอร์พูล btw
Max Vernon

ฉันยังลองด้วย: DBCC FREESYSTEMCACHE ('ALL'); DBCC FREEPROCCACHE; DBCC FREESESSIONCACHE;
Max Vernon

1
@ MaxVernon อาจเป็นคุณลักษณะ "Keep 'em guessin" ;-)
โซโลมอน Rutzky

2
@MaxVernon, ไม่ลืมที่จะดำเนินการในบริบทของฐานข้อมูลก่อนที่จะCHECKPOUNT DBCC DROPCLEANBUFFERS
Dan Guzman
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.