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

12

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

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

Nous pouvons ajouter une VARCHAR(MAX)colonne, 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?

mustaccio
la source

Réponses:

16

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 VARCHAR(MAX)colonne 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 voir cela 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.

Joe Obbish
la source