Se una colonna VARCHAR (MAX) è inclusa in un indice, l'intero valore è sempre memorizzato nelle pagine dell'indice?


12

Lo sto chiedendo per curiosità, ispirandomi a questa domanda .

Sappiamo che i VARCHAR(MAX)valori superiori a 8000 byte non sono memorizzati in righe, ma in pagine LOB separate. Successivamente il recupero di una riga con tale valore richiede due o più operazioni di I / O logiche (in sostanza, una in più di quanto sarebbe teoricamente necessario).

Possiamo aggiungere una VARCHAR(MAX)colonna, come INCLUDEd, a un indice univoco, come dimostrato nella domanda collegata. Se questa colonna ha valori che superano la lunghezza di 8000 byte, tali valori verrebbero comunque memorizzati "in linea" nelle pagine foglia dell'indice o sarebbero anche spostati nelle pagine LOB?

Risposte:


16

I valori che superano 8000 byte non possono essere memorizzati "in linea". Sono memorizzati su pagine LOB. Puoi vederlo con sys.dm_db_index_physical_stats . Inizia con una tabella semplice:

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

Ora inserisci alcune righe con valori che richiedono 8000 byte per la VARCHAR(MAX)colonna e controlla il 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'); 

Non ci sono pagine LOB nell'indice:

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

Ma se aggiungo righe con valori che richiedono 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'); 

Ora ho 1 pagina LOB nell'indice per ogni riga che ho appena inserito:

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

Puoi anche vedere questo con SET STATISTICS IO ON;e la query giusta. Considera la seguente query che esamina solo le righe con 8000 byte:

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

Risultati dopo l'esecuzione:

Conteggio scansioni 1, letture logiche 2560, letture fisiche 0, letture read-ahead 0, letture log lob 0, letture fisiche lob 0, letture read lob 0.

Se invece eseguo una query sulle righe con 8001 byte:

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

Ora vedo lob legge:

Conteggio scansioni 1, letture logiche 20, letture fisiche 0, letture avanti 0, letture logiche lob 5080, letture fisiche lob 0, letture read lob 0.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.