L'indication NOLOCK modifie l'ordre des enregistrements renvoyés

10

Il existe un index cluster sur un Clientchamp de table LastName.

Lorsque je vide simplement tous les enregistrements de la table, ils apparaissent dans l'ordre alphabétique, sauf si un (nolock)indice est utilisé comme dans la requête en question. Cet indice modifie l'ordre des enregistrements. Devrait-il?. Je suis certain qu'aucune autre session n'a une transaction ouverte avec les modifications apportées à cette table (au moins sp_who2ne m'en montre aucune).

Comment expliquer la différence de commande?

Informations supplémentaires tirées des commentaires:

  1. Il n'y a pas de commande par. L'index non groupé doit-il appliquer l'ordre?

  2. Les requêtes renvoient toujours un ordre différent même lorsque vous utilisez une indication d'index spécifiant un index cluster. Devraient-ils? Je me demande pourquoi nolockchange l'ordre des enregistrements retournés sans un changement visible des plans.

  3. J'ai fait un WinDiff sur eux - même sauf pour [le] (nolock)[indice de requête].

ajeh
la source
21
L'astuce ne change pas l'ordre - car il n'y a aucun ordre qui pourrait être changé
a_horse_with_no_name

Réponses:

47

L'apparition d'un jeu de résultats ordonné, sans ORDER BYclause, résulte souvent d'une analyse récupérant les lignes dans l'ordre des index. L'une des raisons pour lesquelles une analyse d'ordre d'index est généralement choisie sous le READ COMMITTEDniveau d'isolement par défaut est qu'elle réduit les risques d'anomalies simultanées indésirables, telles que la rencontre de la même ligne plusieurs fois ou l'omission complète de certaines lignes. Ceci est détaillé à plusieurs endroits, y compris dans cette série d'articles sur les niveaux d'isolement.

Avec une NOLOCKindication de table, ce comportement est détendu et l'accès à la table est effectué sous le READ UNCOMMITTEDniveau d'isolement plus tolérant , qui peut analyser les données dans l'ordre d'allocation au lieu de l'ordre d'index. Comme décrit dans ce lien, la décision d'utiliser ou non une analyse d'ordre d'allocation ou d'index est laissée au moteur de stockage. Ce choix peut changer entre les exécutions sans modification du plan de requête .

Cela peut sembler très abstrait, mais peut être plus facilement démontré avec certaines requêtes utilisant des fonctions non documentées sur la base de données 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);

Résultats de la requête

Les requêtes sont empruntées avec une légère modification à Paul White .

Enfin, juste pour être clair, cette réponse concerne l' apparence d'un ensemble de résultats ordonné. Il n'y a pas d'ordre de présentation garanti sans un niveau supérieur ORDER BY.

Une analyse de l'ordre d'allocation peut se produire dans diverses autres circonstances, par exemple lorsqu'un verrou de niveau table est acquis ou que la base de données est en mode lecture seule. Le parallélisme peut également influencer l'ordre dans lequel les données sont renvoyées. Le point clé est que sans ORDER BY, les données de l'ordre retournées peuvent varier dans le temps par conception.

James L
la source
7
Sympa, beaucoup plus précis que ma tentative non appréciée. Le nœud est bien sûr dans vos deux derniers paragraphes. "Pourquoi" n'a pas vraiment d'importance à la fin. Peut-être que vous aurez plus de chance de réussir cet accord que moi.
Aaron Bertrand
11

James a bien expliqué comment cela fonctionne, mais je voudrais juste répéter une chose: à moins que vous n'utilisiez une fonction de classement, l'ordre des lignes dans le jeu de résultats n'est pas défini . Si vous avez besoin d'un ordre donné, utilisez une order byclause explicite - si vous ne le spécifiez pas, vous dites essentiellement "Je ne me soucie pas du tout de l'ordre", pas "Commandez-le par l'index clusterisé".

Luaan
la source
11

Quand je vide simplement tous les enregistrements de la table

... alors vous ne devriez vous attendre à aucune commande. En fait, la même requête exécutée plusieurs fois peut revenir dans un ordre différent sans avertissement. La raison en est que vos deux requêtes - qui sont des requêtes "différentes" très probablement en raison du texte de requête différent, et non en raison de l'indice - ont des plans d'exécution différents (et la différence peut être subtile, comme un itérateur qui a la même apparence dans les deux plans, mais il ordered: truen'y en a qu'un, ou un nombre très différent de lignes estimées car une a été compilée avant un changement majeur de données). Il se pourrait également qu'une analyse de l'ordre d'allocation soit effectuée, comme James l'a souligné à juste titre dans sa réponse.

Dans tous les cas, puisque vous exécutez une requête sans ORDER BY, SQL Server déduit que vous ne vous souciez pas de l'ordre, et s'éteint donc et détermine la façon la plus efficace de renvoyer les lignes (il ne se soucie pas de l'ordre si vous ne le faites pas ).

Permettez-moi de le dire très clairement:

Si vous voulez ou attendez une certaine commande, ajoutez une clause ORDER BY

Cela est apparu auparavant:

Et j'ai blogué à ce sujet:

Voici une citation de ce dernier qui réitère ce que j'ai dit pour répondre à votre commentaire sur l'utilisation d'un indice au lieu d'une ORDER BYclause:

Même dans le cas d'un index avec indice, l'index sera utilisé (si possible, sinon une erreur dans la plupart des cas), mais ce n'est pas parce que l'index est utilisé que les résultats seront renvoyés triés par la ou les clés dans cet indice. Vous avez toujours besoin d'un ORDER BYpour assurer le tri par la ou les clés d'index.

Conor Cunningham - un gars assez intelligent, directement responsable d'une grande partie de ce que fait SQL Server lorsqu'il traite une requête pour vous - en a également parlé ici:

Veuillez lire et ajouter une ORDER BYclause à vos requêtes avant de vous plaindre d'un tri différent ou inattendu.

Aaron Bertrand
la source