Il suggerimento NOLOCK modifica l'ordine dei record restituiti


11

C'è un indice cluster su un Clientcampo tabella LastName.

Quando eseguo semplicemente il dump di tutti i record dalla tabella, questi vengono visualizzati in ordine alfabetico a meno che non (nolock)venga utilizzato un suggerimento come nella query in questione. Quel suggerimento cambia l'ordine dei record. Dovrebbe?. Sono sicuro che nessun'altra sessione ha una transazione aperta con le modifiche a quella tabella (almeno sp_who2non me ne mostra alcuna).

Come si può spiegare la differenza nell'ordine?

Informazioni aggiuntive tratte dai commenti:

  1. Non c'è ordine per. L'indice non cluster dovrebbe far rispettare l'ordine?

  2. Le query restituiscono comunque un ordine diverso anche quando si utilizza un suggerimento indice che specifica un indice cluster. Dovrebbero? Mi chiedo perché nolockcambi l'ordine dei record restituiti senza un cambiamento visibile dei piani.

  3. Ho fatto un WinDiff su di loro - lo stesso tranne [il] (nolock)[suggerimento per la query].


21
Il suggerimento non cambia l'ordine - perché non esiste un ordine che potrebbe essere cambiato
a_horse_with_no_name

Risposte:


47

L'aspetto di un set di risultati ordinato, senza una ORDER BYclausola, spesso deriva da una scansione che recupera le righe in ordine di indice. Uno dei motivi per cui una scansione dell'ordine degli indici viene generalmente scelta sotto il READ COMMITTEDlivello di isolamento predefinito è che riduce le possibilità di anomalie di concorrenza indesiderate come incontrare più volte la stessa riga o saltare completamente alcune righe. Questo è dettagliato in diversi punti, incluso in questa serie di articoli sui livelli di isolamento.

Con un NOLOCKsuggerimento sulla tabella, questo comportamento è rilassato e l'accesso alla tabella viene eseguito con il READ UNCOMMITTEDlivello di isolamento più tollerante , che può eseguire la scansione dei dati in ordine di allocazione anziché in ordine di indice. Come descritto in quel collegamento, la decisione sull'utilizzo di una scansione dell'ordine di allocazione o dell'ordine dell'indice viene lasciata al motore di archiviazione. Questa scelta può cambiare tra le esecuzioni senza una modifica nel piano di query .

Questo può sembrare molto astratto, ma può essere più facilmente dimostrato con alcune query che utilizzano funzioni non documentate sul database AdventureWorks2012 .

USE AdventureWorks2012;
GO
-- Appears to be ordered by BusinessEntityID
-- File:Page:Slot goes up and down several times
-- Show physical locations with sys.fn_PhysLocFormatter (undocumented)
SELECT
    P.BusinessEntityID,
    [(File:Page:Slot)] =
        sys.fn_PhysLocFormatter(%%physloc%%)
FROM Person.Person AS P;

-- Same query with TABLOCK or NOLOCK
-- Allocation-order (IAM) scan
-- Now appears to be ordered by File:Page:Slot instead of BusinessEntityID
SELECT P.BusinessEntityID,
    [(File:Page:Slot)] =
        sys.fn_PhysLocFormatter(%%physloc%%)
FROM Person.Person AS P WITH (NOLOCK);

Risultati della query

Le domande sono prese in prestito con lievi modifiche da Paul White .

Infine, per essere chiari, questa risposta riguarda l' aspetto di un set di risultati ordinato. Non esiste un ordine di presentazione garantito senza un livello superiore ORDER BY.

Una scansione dell'ordine di allocazione può verificarsi in una varietà di altre circostanze, ad esempio quando viene acquisito un blocco a livello di tabella o il database è in modalità di sola lettura. Il parallelismo può anche influenzare l'ordine in cui vengono restituiti i dati. Il punto chiave è che senza ORDER BY, i dati dell'ordine in cui vengono restituiti possono variare nel tempo in base alla progettazione.


7
Bello, molto più specifico del mio tentativo non apprezzato. Il punto cruciale è nei tuoi ultimi due paragrafi, ovviamente. "Perché" non ha molta importanza alla fine. Forse avrai più fortuna a suonare quell'accordo che a me.
Aaron Bertrand

12

Quando ho semplicemente scaricato tutti i record dalla tabella

... allora non dovresti aspettarti alcun ordine. In effetti la stessa query eseguita più volte potrebbe tornare in un ordine diverso senza preavviso. Il motivo è che le tue due query - che sono query "diverse" molto probabilmente a causa del diverso testo della query, non a causa del suggerimento - hanno piani di esecuzione diversi (e la differenza può essere sottile, come un iteratore che sembra lo stesso in entrambi i piani, ma ne ha ordered: truesolo uno; o un numero notevolmente diverso di righe stimate perché una è stata compilata prima di un importante cambio di dati). Potrebbe anche essere che venga eseguita una scansione dell'ordine di allocazione, come James ha giustamente indicato nella sua risposta.

In ogni caso, poiché si esegue una query senza ORDER BY, SQL Server deduce che non ti interessa l'ordine, quindi si spegne e determina il modo più efficiente per restituire le righe (non importa l'ordine se non lo fai ).

Vorrei chiarire questo:

Se desideri o ti aspetti un determinato ordine, aggiungi una clausola ORDER BY

Questo è emerso prima:

E ho blog su questo:

Ecco una citazione di quest'ultimo che ribadisce ciò che ho detto per rispondere al tuo commento sull'utilizzo di un suggerimento sull'indice anziché su una ORDER BYclausola:

Anche nel caso di un indice suggerito, verrà utilizzato l'indice (se possibile, altrimenti un errore nella maggior parte dei casi), ma solo perché l'indice viene utilizzato non significa che i risultati verranno restituiti ordinati in base alle chiavi in quell'indice. È ancora necessario ORDER BYper garantire l'ordinamento in base alla chiave o alle chiavi di indice.

Conor Cunningham - un ragazzo piuttosto intelligente, direttamente responsabile di gran parte di ciò che fa SQL Server quando elabora una query per te - ha anche scritto un blog al riguardo qui:

Leggete e quindi aggiungete una ORDER BYclausola alle vostre domande prima di lamentarvi di un ordinamento diverso o imprevisto.


11

James ha spiegato bene come funziona, ma vorrei solo ribadire una cosa: a meno che tu non usi una funzione di ordinamento, l'ordine delle righe nel set di risultati non è definito . Se hai bisogno di un determinato ordine, usa una order byclausola esplicita - se non lo specifichi, sostanzialmente stai dicendo "Non mi interessa affatto l'ordine", non "Ordinalo per indice cluster".

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.