Condividi tramite


Lettura di pagine

L'I/O di un'istanza di Motore di database di SQL Server include letture logiche e fisiche. La lettura logica viene eseguita ogni volta che Motore di database richiede una pagina dalla cache buffer. Se la pagina non si trova nella cache buffer, viene prima eseguita una lettura fisica per copiare la pagina dal disco alla cache.

Le richieste di lettura generate da un'istanza di Motore di database sono controllate dal motore relazionale e ottimizzate dal motore di archiviazione. Il motore relazionale determina il metodo di accesso più efficace, ad esempio scansione di tabella, scansione di indice o lettura basata su chiavi. I metodi di accesso e i componenti di Gestione buffer del motore di archiviazione determinano il modello generale delle letture da eseguire e ottimizzano le letture necessarie per implementare il metodo di accesso. Il thread che esegue il batch pianifica le operazioni di lettura.

Read-Ahead

Motore di database supporta un meccanismo di ottimizzazione delle prestazioni detto read-ahead. Questo meccanismo anticipa le pagine di dati e di indice necessarie per soddisfare il piano di esecuzione della query e inserisce le pagine nella cache buffer prima che vengano effettivamente utilizzate dalla query. In questo modo viene consentita la sovrapposizione di operazioni di calcolo e di I/O ed è possibile utilizzare al meglio sia la CPU che il disco.

Il meccanismo read-ahead consente la lettura da parte di Motore di database di un massimo di 64 pagine contigue (512 KB) incluse in un unico file. La lettura viene eseguita come singola lettura non sequenziale nel numero appropriato di buffer, probabilmente non contigui, nella cache buffer. Se alcune pagine incluse nell'intervallo sono già presenti nella cache buffer, la pagina corrispondente della lettura verrà scartata dopo il completamento dell'operazione di lettura. Le pagine alle due estremità dell'intervallo possono inoltre venire rimosse se nella cache sono già presenti le pagine corrispondenti.

Vi sono due tipi di meccanismi read-ahead, uno per le pagine di dati e uno per le pagine di indice.

Lettura delle pagine di dati

Le scansioni di tabella utilizzate per leggere le pagine di dati sono molto efficaci in Motore di database. Nelle pagine IAM (Index Allocation Map, mappa di allocazione degli indici) di un database di SQL Server vengono elencati gli extent utilizzati da una tabella o da un indice. Il motore di archiviazione può leggere la pagina IAM per creare un elenco ordinato degli indirizzi di disco che è necessario leggere. Questo consente al motore di archiviazione di ottimizzare le operazioni di I/O come se si trattasse di letture sequenziali di grandi dimensioni eseguite in sequenza, in base alla relativa posizione nel disco. Per ulteriori informazioni sulle pagine IAM, vedere Gestione dello spazio utilizzato dagli oggetti.

Lettura delle pagine di indice

Il motore di archiviazione legge le pagine di indice in modo seriale, in base all'ordine delle chiavi. Nella figura seguente è ad esempio illustrata una rappresentazione semplificata di un set di pagine foglia contenente un set di chiavi e il nodo di indice intermedio che esegue il mapping delle pagine foglia. Per ulteriori informazioni sulla struttura delle pagine in un indice, vedere Strutture degli indici cluster.

Mapping basato su chiave tra il nodo di indice intermedio e le pagine foglia

Il motore di archiviazione utilizza le informazioni della pagina di indice intermedio sopra il livello foglia per pianificare letture seriali per le pagine che contengono le chiavi. Se vengono richieste tutte le chiavi da ABC a DEF, il motore di archiviazione legge innanzitutto la pagina di indice sopra la pagina foglia, non limitandosi, tuttavia, alla semplice lettura in sequenza di ogni pagina di dati, dalla 504 alla 556, ovvero l'ultima che include chiavi comprese nell'intervallo specificato. Al contrario, il motore di archiviazione esegue la scansione della pagina di indice intermedio, crea un elenco delle pagine foglia da leggere e pianifica quindi tutte le letture in base all'ordine delle chiavi. Il motore di archiviazione riconosce inoltre che le pagine 504/505 e 527/528 sono contigue ed esegue una singola lettura sequenziale per recuperare le pagine adiacenti in una sola operazione. Se in un'operazione seriale è necessario recuperare molte pagine, il motore di archiviazione pianifica un blocco di letture per volta. Quando viene completato un subset di letture, il motore di archiviazione pianifica un numero equivalente di nuove letture fino a quando non sono state pianificate tutte le letture necessarie.

Il motore di archiviazione utilizza la prelettura per rendere più veloci le ricerche nelle tabelle di base da indici non cluster. Le righe foglia di un indice non cluster contengono puntatori alle righe di dati che includono i singoli valori di chiave specifici. Mentre il motore di archiviazione legge le pagine foglia dell'indice non cluster, inizia anche a pianificare le letture asincrone per le righe di dati i cui puntatori sono già stati recuperati. In questo modo, il motore di archiviazione può recuperare le righe di dati dalla tabella sottostante prima di avere completato la scansione dell'indice non cluster. La prelettura viene utilizzata indipendentemente dal fatto che alla tabella sia associato o meno un indice cluster. In SQL Server Enterprise Edition la prelettura viene utilizzata con maggiore frequenza rispetto ad altre edizioni di SQL Server, di conseguenza il read-ahead viene effettuato su un numero maggiore di pagine. In nessuna edizione è possibile configurare il livello di prelettura. Per ulteriori informazioni sugli indici non cluster, vedere Strutture degli indici non cluster.

Scansione avanzata

In SQL Server Enterprise Edition la funzionalità di scansione avanzata consente la condivisione di scansioni complete di tabella tra più attività. Se in base al piano di esecuzione di un'istruzione Transact-SQL è necessaria la scansione delle pagine di dati di una tabella e Motore di database rileva che tale tabella è già sottoposta a scansione da un altro piano di esecuzione, Motore di database unisce la seconda scansione alla prima nella posizione corrente della seconda scansione. Motore di database legge ogni pagina una sola volta e passa le righe di ognuna a entrambi i piani di esecuzione. Questa procedura continua fino a quando viene raggiunta la fine della tabella.

A questo punto, il primo piano di esecuzione dispone dei risultati completi della scansione, mentre il secondo piano di esecuzione deve ancora recuperare le pagine di dati lette prima dell'unione alla scansione in corso. La scansione del secondo piano di esecuzione riprende quindi dalla prima pagina di dati della tabella e termina in corrispondenza della posizione a partire dalla quale si è unita alla prima scansione. È possibile combinare in questo modo un numero qualsiasi di scansioni. Motore di database continua a esaminare in ciclo tutte le pagine di dati fino al completamento di tutte le scansioni. Questo meccanismo è anche detto "scansione ciclica" ed è il motivo per cui non è possibile garantire l'ordine dei risultati restituiti da un'istruzione SELECT senza una clausola ORDER BY.

Si supponga, ad esempio, che sia disponibile una tabella con 500.000 pagine. L'Utente A esegue un'istruzione Transact-SQL che richiede una scansione della tabella. Quando tale scansione ha già elaborato 100.000 pagine, l'Utente B esegue un'altra istruzione Transact-SQL che esegue la scansione della stessa tabella. Motore di database pianifica un set di richieste di lettura per le pagine successive alla 100.001 e passa le righe di ogni pagina a entrambe le scansioni. Quando la scansione raggiunge la pagina 200.000, l'Utente C esegue un'altra istruzione Transact-SQL che esegue la scansione della stessa tabella. A partire dalla pagina 200.001, Motore di database passa a tutte e tre le scansioni le righe di ogni pagina che legge. Al termine della lettura della riga 500.000, la scansione per l'Utente A è completata e quelle per l'Utente B e l'Utente C ricominciano la lettura a partire dalla pagina 1. Quando Motore di database raggiunge la pagina 100.000, la scansione per l'Utente B è completata. La scansione per l'Utente C continua da sola fino a raggiungere la pagina 200.000. A questo punto, tutte le scansioni sono state completate.

Senza la scansione avanzata, gli utenti dovrebbero condividere lo spazio nel buffer, contendendosi il disco. Le stesse pagine verrebbero inoltre lette una volta per ogni utente, anziché essere lette una sola volta e condivise tra più utenti, provocando un peggioramento delle prestazioni e un sovraccarico delle risorse.