Nếu cột VARCHAR (MAX) được bao gồm trong một chỉ mục, toàn bộ giá trị có luôn được lưu trữ trong (các) trang chỉ mục không?


12

Tôi đang hỏi điều này vì tò mò, được truyền cảm hứng bởi câu hỏi này .

Chúng tôi biết rằng VARCHAR(MAX)các giá trị dài hơn 8000 byte không được lưu trữ trong các hàng, mà trong các trang LOB riêng biệt. Sau đó, việc truy xuất một hàng có giá trị như vậy đòi hỏi hai hoặc nhiều thao tác IO logic (về cơ bản, một hoạt động nhiều hơn so với lý thuyết là cần thiết).

Chúng ta có thể thêm một VARCHAR(MAX)cột, như INCLUDEd, vào một chỉ mục duy nhất, như được thể hiện trong câu hỏi được liên kết. Nếu cột này có các giá trị vượt quá 8000 byte, thì các giá trị đó vẫn được lưu trữ "nội tuyến" trong các trang lá chỉ mục hay chúng cũng sẽ được chuyển đến các trang LOB?

Câu trả lời:


16

Các giá trị vượt quá 8000 byte không thể được lưu trữ "nội tuyến". Chúng được lưu trữ trên các trang LOB. Bạn có thể thấy điều này với sys.dm_db_index_physical_stats . Bắt đầu với một bảng đơn giản:

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);

Bây giờ chèn một số hàng với các giá trị mất 8000 byte cho VARCHAR(MAX)cột và kiểm tra 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'); 

Không có trang LOB trong chỉ mục:

╔═════════════╦════════════════════╦══════════════════════╦════════════╦══════════════╗
║ 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 ║
╚═════════════╩════════════════════╩══════════════════════╩════════════╩══════════════╝

Nhưng nếu tôi thêm các hàng có giá trị mất 8001 byte:

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'); 

Bây giờ tôi có 1 trang LOB trong chỉ mục cho mỗi hàng tôi vừa chèn:

╔═════════════╦════════════════════╦══════════════════════╦════════════╦══════════════╗
║ 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 ║
╚═════════════╩════════════════════╩══════════════════════╩════════════╩══════════════╝

Bạn cũng có thể thấy điều này với SET STATISTICS IO ON;và truy vấn đúng. Hãy xem xét các truy vấn sau chỉ nhìn vào các hàng có 8000 byte:

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

Kết quả khi thực hiện:

Quét số 1, đọc logic 2560, đọc vật lý 0, đọc trước đọc 0, đọc logic 0, đọc vật lý lob 0, đọc trước đọc 0, đọc trước 0.

Thay vào đó, nếu tôi truy vấn các hàng có 8001 byte:

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

Bây giờ tôi thấy lob đọc:

Quét số 1, đọc logic 20, đọc vật lý 0, đọc trước đọc 0, đọc logic lob 5080, đọc vật lý lob 0, đọc trước đọc 0, đọc trước 0.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookie và Chính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.