web-dev-qa-db-fra.com

Si une colonne VARCHAR (MAX) est incluse dans un index, la valeur entière est-elle toujours stockée dans les pages d'index?

Je pose cette question par curiosité, étant inspiré par cette question .

Nous savons que VARCHAR(MAX) les valeurs supérieures à 8 000 octets ne sont pas stockées dans des lignes, mais dans des pages LOB distinctes. Par la suite, la récupération d'une ligne avec une telle valeur nécessite deux ou plusieurs opérations logiques IO (essentiellement, une de plus qu'autrement serait théoriquement nécessaire).

Nous pouvons ajouter une colonne VARCHAR(MAX), comme INCLUDEd, à un index unique, comme démontré dans la question liée. Si cette colonne a des valeurs supérieures à 8 000 octets, ces valeurs seront-elles toujours stockées "en ligne" dans les pages de feuille d'index, ou seront-elles également déplacées vers les pages LOB?

12
mustaccio

Les valeurs qui dépassent 8 000 octets ne peuvent pas être stockées "en ligne". Ils sont stockés sur des pages LOB. Vous pouvez le voir avec sys.dm_db_index_physical_stats . Commencez avec un simple tableau:

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

Insérez maintenant quelques lignes avec des valeurs qui prennent 8000 octets pour la colonne VARCHAR(MAX) et consultez le 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'); 

Il n'y a pas de pages LOB dans l'index:

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

Mais si j'ajoute des lignes avec des valeurs qui prennent 8001 octets:

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

Maintenant, j'ai 1 page LOB dans l'index pour chaque ligne que je viens d'insérer:

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

Vous pouvez également le voir avec SET STATISTICS IO ON; Et la bonne requête. Considérez la requête suivante qui ne regarde que les lignes de 8 000 octets:

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

Résultats à l'exécution:

Nombre de balayages 1, lectures logiques 2560, lectures physiques 0, lectures anticipées 0, lectures logiques 0, lob lectures physiques 0, lob lectures anticipées 0.

Si j'interroge plutôt les lignes avec 8001 octets:

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

Maintenant, je vois que lob lit:

Nombre de balayages 1, lectures logiques 20, lectures physiques 0, lectures anticipées 0, lectures logiques 5080, lob lectures physiques 0, lob lectures anticipées 0.

16
Joe Obbish