Los valores que superan los 8000 bytes no se pueden almacenar "en línea". Se almacenan en páginas LOB. Puede ver esto con sys.dm_db_index_physical_stats . Comience con una tabla simple:
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);
Ahora inserte algunas filas con valores que toman 8000 bytes para la VARCHAR(MAX)
columna y revise el 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');
No hay páginas LOB en el índice:
╔═════════════╦════════════════════╦══════════════════════╦════════════╦══════════════╗
║ 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 ║
╚═════════════╩════════════════════╩══════════════════════╩════════════╩══════════════╝
Pero si agrego filas con valores que toman 8001 bytes:
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');
Ahora tengo 1 página LOB en el índice para cada fila que acabo de insertar:
╔═════════════╦════════════════════╦══════════════════════╦════════════╦══════════════╗
║ 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 ║
╚═════════════╩════════════════════╩══════════════════════╩════════════╩══════════════╝
También puede ver esto con SET STATISTICS IO ON;
y la consulta correcta. Considere la siguiente consulta que solo mira las filas con 8000 bytes:
SELECT SUM(LEN(MAX_VERNON_WAS_HERE))
FROM #LOB_FOR_ME
WHERE ID = 1;
Resultados al ejecutar:
Cuenta de escaneo 1, lecturas lógicas 2560, lecturas físicas 0, lecturas de lectura anticipada 0, lecturas lógicas lob 0, lecturas físicas lob 0, lecturas de lectura lob 0.
Si, en cambio, consulto las filas con 8001 bytes:
SELECT SUM(LEN(MAX_VERNON_WAS_HERE))
FROM #LOB_FOR_ME
WHERE ID = 2;
Ahora veo lob lee:
Recuento de escaneo 1, lecturas lógicas 20, lecturas físicas 0, lecturas anticipadas 0, lecturas lógicas lob 5080, lecturas físicas lob 0, lecturas anticipadas lob 0.