หากคอลัมน์ VARCHAR (MAX) รวมอยู่ในดัชนีค่าทั้งหมดจะถูกเก็บไว้ในหน้าดัชนีหรือไม่?


12

ฉันขอสิ่งนี้ด้วยความอยากรู้อยากเห็นได้รับแรงบันดาลใจจากคำถามนี้

เรารู้ว่าVARCHAR(MAX)ค่าที่ยาวกว่า 8000 ไบต์จะไม่ถูกเก็บไว้ในแถว แต่ในหน้า LOB แยกต่างหาก หลังจากนั้นการดึงแถวที่มีค่าดังกล่าวจำเป็นต้องมีการดำเนินการ IO แบบตรรกะสองอย่างหรือมากกว่านั้น

เราสามารถเพิ่มVARCHAR(MAX)คอลัมน์เป็นINCLUDEd ไปยังดัชนีที่ไม่ซ้ำกันดังที่แสดงในคำถามที่เชื่อมโยง หากคอลัมน์นี้มีค่าที่มีความยาวเกิน 8000 ไบต์ค่าดังกล่าวจะยังคงถูกเก็บไว้ "แบบอินไลน์" ในหน้าดัชนีใบหรือจะย้ายไปยังหน้า LOB หรือไม่

คำตอบ:


16

ค่าที่เกิน 8000 ไบต์ไม่สามารถจัดเก็บ "แบบอินไลน์" พวกเขาจะถูกเก็บไว้ในหน้า LOB คุณสามารถดูนี้กับsys.dm_db_index_physical_stats เริ่มด้วยตารางง่ายๆ

USE tempdb;

DROP TABLE IF EXISTS #LOB_FOR_ME;

CREATE TABLE #LOB_FOR_ME (
ID BIGINT,
MAX_VERNON_WAS_HERE VARCHAR(MAX) 
);

CREATE INDEX IX ON #LOB_FOR_ME (ID) INCLUDE (MAX_VERNON_WAS_HERE);

ตอนนี้แทรกบางแถวด้วยค่าที่ใช้ 8000 ไบต์สำหรับVARCHAR(MAX)คอลัมน์และตรวจสอบ DMF:

USE tempdb;

INSERT INTO #LOB_FOR_ME
SELECT 1, REPLICATE('Z', 8000)
FROM master..spt_values;

SELECT index_level, index_type_desc, alloc_unit_type_desc, page_count, record_count
FROM sys.dm_db_index_physical_stats(DB_ID(), OBJECT_ID('#LOB_FOR_ME'), 2, NULL , 'DETAILED'); 

ไม่มีหน้า LOB ในดัชนี:

╔═════════════╦════════════════════╦══════════════════════╦════════════╦══════════════╗
 index_level   index_type_desc    alloc_unit_type_desc  page_count  record_count 
╠═════════════╬════════════════════╬══════════════════════╬════════════╬══════════════╣
           0  NONCLUSTERED INDEX  IN_ROW_DATA                 2540          2540 
           1  NONCLUSTERED INDEX  IN_ROW_DATA                   18          2540 
           2  NONCLUSTERED INDEX  IN_ROW_DATA                    1            18 
╚═════════════╩════════════════════╩══════════════════════╩════════════╩══════════════╝

แต่ถ้าฉันเพิ่มแถวที่มีค่าที่รับ 8001 ไบต์:

USE tempdb;

INSERT INTO #LOB_FOR_ME
SELECT 2, REPLICATE(CAST('Z' AS VARCHAR(MAX)), 8001)
FROM master..spt_values;

SELECT index_level, index_type_desc, alloc_unit_type_desc, page_count, record_count
FROM sys.dm_db_index_physical_stats(DB_ID(), OBJECT_ID('#LOB_FOR_ME'), 2, NULL , 'DETAILED'); 

ตอนนี้ฉันมี 1 LOB หน้าในดัชนีสำหรับทุกแถวที่ฉันเพิ่งแทรก:

╔═════════════╦════════════════════╦══════════════════════╦════════════╦══════════════╗
 index_level   index_type_desc    alloc_unit_type_desc  page_count  record_count 
╠═════════════╬════════════════════╬══════════════════════╬════════════╬══════════════╣
           0  NONCLUSTERED INDEX  IN_ROW_DATA                 2556          5080 
           1  NONCLUSTERED INDEX  IN_ROW_DATA                   18          2556 
           2  NONCLUSTERED INDEX  IN_ROW_DATA                    1            18 
           0  NONCLUSTERED INDEX  LOB_DATA                    2540          2540 
╚═════════════╩════════════════════╩══════════════════════╩════════════╩══════════════╝

นอกจากนี้คุณยังสามารถดูได้ด้วยSET STATISTICS IO ON;และแบบสอบถามที่ถูกต้อง พิจารณาแบบสอบถามต่อไปนี้ที่ดูเฉพาะแถวที่มี 8000 ไบต์เท่านั้น:

SELECT SUM(LEN(MAX_VERNON_WAS_HERE))
FROM #LOB_FOR_ME
WHERE ID = 1;

ผลลัพธ์เมื่อดำเนินการ:

จำนวนการสแกน 1, การอ่านเชิงตรรกะ 2560, การอ่านทางกายภาพ 0, การอ่านล่วงหน้าอ่าน 0, lob ตรรกะอ่าน 0, lob การอ่านทางกายภาพ 0, lob การอ่านล่วงหน้าอ่าน 0

ถ้าฉันค้นหาแถวด้วย 8001 ไบต์แทน:

SELECT SUM(LEN(MAX_VERNON_WAS_HERE))
FROM #LOB_FOR_ME
WHERE ID = 2;

ตอนนี้ฉันเห็นลูกเทนนิสอ่าน:

จำนวนการสแกน 1, การอ่านเชิงตรรกะ 20, การอ่านทางกายภาพ 0, การอ่านล่วงหน้าอ่าน 0, lob ตรรกะอ่าน 5080, lob การอ่านทางกายภาพ 0, lob การอ่านล่วงหน้าอ่าน 0

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.