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 cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.