Perché più (e numero variabile di) letture logiche con read ahead (prefetch)?


8

Dopo aver creato il database tpch nel mio SQL Server, ho provato di seguito la query:

    set statistics io on
    DBCC DROPCLEANBUFFERS;        
    select top 100 * from dbo.lineitem order by l_partkey;

La tabella lineitem ha un indice non cluster su l_partkey. Ho inviato le query precedenti per diverse volte e ho scoperto che le letture logiche variano ogni volta:

    Table 'lineitem'. Scan count 1, logical reads 1019, physical reads 4, read-ahead reads 1760, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'lineitem'. Scan count 1, logical reads 1007, physical reads 4, read-ahead reads 1720, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'lineitem'. Scan count 1, logical reads 1030, physical reads 4, read-ahead reads 1792, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Dal post qui: il conteggio logico delle letture varia , so che potrebbe essere causato dal comportamento di lettura anticipata.

MA esattamente perché leggere in anticipo potrebbe causare letture più logiche? Come cambia il comportamento di SQL Server? Come se SQL Server potesse leggere più pagine indice dal momento che è nella cache?

Ad ogni modo, ho disabilitato la lettura anticipata ed emettere nuovamente la query sopra. Ora riporta la stessa quantità di letture logiche ogni volta. MA le letture logiche sono molto più piccole !!

    Table 'lineitem'. Scan count 1, logical reads 404, physical reads 160, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Quindi la mia domanda è: perché la funzione di lettura anticipata potrebbe causare molte più e varie letture logiche contano?

Per curiosità, ho provato un'altra query senza "ordina per":

    select top 100 * from dbo.lineitem

Ecco il risultato senza leggere in anticipo:

    Table 'lineitem'. Scan count 1, logical reads 5, physical reads 3, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Ecco il risultato con la lettura in anticipo:

    Table 'lineitem'. Scan count 1, logical reads 15, physical reads 2, read-ahead reads 3416, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Quello con read ahead ha ancora letture più logiche. Allora perchè?

Risposte:


9

Il piano di query per l' ORDER BY l_partkeyesempio legge quasi certamente l'indice non cluster in ordine (con read-ahead), seguito da una Ricerca chiave per recuperare le colonne scoperte.

L'operatore Join loop nidificati sopra la ricerca utilizza probabilmente prefetching aggiuntivo ( WithOrderedPrefetch) per la ricerca. Vedi il seguente articolo che ho scritto per tutti i dettagli:

Inoltre, come ho detto in risposta alle domande e risposte collegate, il numero di letture read-ahead dipende dalle caratteristiche del sottosistema di temporizzazione e archiviazione. Lo stesso tipo di considerazioni si applica al prefetch di Ricerca nell'unione di cicli nidificati.

Si noti che SQL Server emette read-ahead per le pagine che potrebbero essere necessarie per la scansione dell'indice, ma ciò non è limitato dalla TOPspecifica nella query. Il TOPè un elemento di processore di query, mentre la lettura in anticipo è controllato dal motore di archiviazione.

Le attività sono abbastanza separate: read-ahead (e prefetching) emettono I / O asincroni per le pagine che potrebbero essere necessarie per la Scansione (o Ricerca).

A seconda dell'ordine in cui gli I / O vengono effettivamente completati e messi a disposizione delle righe al Query Processor (tra le altre cose), il numero di pagine effettivamente toccate (letture logiche) o lette fisicamente può variare. Notare in particolare che il prefetch con ritardo di ricerca contribuisce anche alle letture logiche quando verifica se una pagina necessaria per il lookup è già in memoria o meno.

Quindi, tutto si riduce alla tempistica dettagliata delle operazioni di sovrapposizione: il processore di query inizierà a chiudere la pipeline di esecuzione della query non appena il numero richiesto di righe (100) è stato visualizzato nell'iteratore superiore. Piuttosto, quanti I / O asincroni (read-ahead o prefetch) saranno stati emessi o completati a quel punto è essenzialmente non deterministico.

È possibile disabilitare il prefetching Unisci loop annidati con flag di traccia 8744 per esplorare ulteriormente questo. Ciò rimuoverà la WithOrderedPrefetchproprietà dall'unione dei cicli nidificati. Di solito lo uso OPTION (QUERYTRACEON 8744)sulla query stessa. In ogni caso, devi essere sicuro di non riutilizzare un piano memorizzato nella cache con prefetch. Svuotare la cache del piano ogni volta o forzare la ricompilazione di una query OPTION (RECOMPILE).

Le letture logiche sono una semplice misura del numero di pagine della cache toccate per conto della query. Laddove il read-ahead (e / o il prefetching) è abilitato, è possibile toccare più (e diverse!) Pagine di indice e dati per emettere il read-ahead o come parte dell'attività di prefetching.

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.