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.