Якщо стовпець VARCHAR (MAX) включений до індексу, чи завжди все значення зберігається на сторінці (их) індексу?


12

Я запитую це з цікавості, надихаючись цим питанням .

Ми знаємо, що VARCHAR(MAX)значення довше 8000 байт зберігаються не в рядках, а на окремих сторінках LOB. Згодом для отримання рядка з таким значенням потрібні дві або більше логічних операцій вводу-виводу (по суті, теоретично буде потрібно одна більше, ніж інакше).

Ми можемо додати 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, логічне зчитування лобі 0, лобічне фізичне зчитування 0, лобічне зчитування попереднє зчитування 0.

Якщо я замість цього запитую рядки з 8001 байтами:

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

Тепер я бачу, що лоб гласить:

Кількість сканувань 1, логічне зчитування 20, фізичне зчитування 0, зчитування вперед зчитування 0, логічне зчитування лобі 5080, лобічне фізичне зчитування 0, лобічне зчитування попереднє зчитування 0.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.