La sugerencia NOLOCK cambia el orden de los registros devueltos

10

Hay un índice agrupado en un Clientcampo de tabla LastName.

Cuando simplemente vuelco todos los registros de la tabla, aparecen en orden alfabético a menos que (nolock)se use una pista como en la consulta en cuestión. Esa pista cambia el orden de los registros. ¿Deberia?. Estoy seguro de que ninguna otra sesión tiene una transacción abierta con los cambios en esa tabla (al menos sp_who2no me muestra ninguna).

¿Cómo se puede explicar la diferencia en el orden?

Información adicional extraída de los comentarios:

  1. No hay orden por. ¿Debería el índice no agrupado imponer el orden?

  2. Las consultas aún devuelven un orden diferente incluso cuando se utiliza una sugerencia de índice que especifica un índice agrupado. ¿Deberían ellos? Me pregunto por qué nolockcambia el orden de los registros devueltos sin un cambio visible de los planes.

  3. Hice un WinDiff en ellos, lo mismo a excepción de [la] (nolock)[sugerencia de consulta].

ajeh
fuente
21
La sugerencia no cambia el orden, porque no hay ningún orden que pueda modificarse
A_horse_with_no_name

Respuestas:

47

La aparición de un conjunto de resultados ordenado, sin una ORDER BYcláusula, a menudo resulta de un escaneo que recupera filas en orden de índice. Una razón por la que generalmente se elige una exploración de orden de índice bajo el READ COMMITTEDnivel de aislamiento predeterminado es que reduce las posibilidades de anomalías de concurrencia no deseadas, como encontrar la misma fila varias veces o omitir por completo algunas filas. Esto se detalla en varios lugares, incluso en esta serie de artículos sobre niveles de aislamiento.

Con una NOLOCKsugerencia de tabla, este comportamiento es relajado y el acceso a la tabla se realiza bajo el READ UNCOMMITTEDnivel de aislamiento más tolerante , que puede escanear datos en orden de asignación en lugar de orden de índice. Como se describe en ese enlace, la decisión sobre si utilizar una exploración de orden de asignación o de orden de índice se deja al motor de almacenamiento. Esta opción puede cambiar entre ejecuciones sin un cambio en el plan de consulta .

Esto puede sonar muy abstracto, pero se puede demostrar más fácilmente con algunas consultas utilizando funciones no documentadas en la base de datos 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);

Resultados de consultas

Las consultas se toman prestadas con una ligera modificación de Paul White .

Finalmente, para ser claros, esta respuesta trata sobre la apariencia de un conjunto de resultados ordenado. No hay orden de presentación garantizada sin un nivel superior ORDER BY.

Una exploración de orden de asignación puede ocurrir en una variedad de otras circunstancias, como cuando se adquiere un bloqueo a nivel de tabla o la base de datos está en modo de solo lectura. El paralelismo también puede influir en el orden en que se devuelven los datos. El punto clave es que sin ellos ORDER BY, los datos de los pedidos devueltos pueden variar con el tiempo según el diseño.

James L
fuente
77
Agradable, mucho más específico que mi intento poco apreciado. El quid está en tus dos últimos párrafos, por supuesto. "Por qué" realmente no importa al final. Quizás tengas mejor suerte tocando ese acorde que yo.
Aaron Bertrand
11

James explicó muy bien cómo funciona esto, pero solo me gustaría reiterar una cosa: a menos que use una función de orden, el orden de las filas en el conjunto de resultados no está definido . Si necesita un pedido determinado, use una order bycláusula explícita : si no lo especifica, básicamente está diciendo "No me importa el orden en absoluto", no "Ordenarlo por el índice agrupado".

Luaan
fuente
11

Cuando simplemente vuelco todos los registros de la tabla

... entonces no deberías esperar ningún pedido. De hecho, la misma consulta ejecutada varias veces podría volver en un orden diferente sin previo aviso. La razón es que sus dos consultas, que son consultas "diferentes" probablemente debido al texto de consulta diferente, no debido a la sugerencia, tienen diferentes planes de ejecución (y la diferencia puede ser sutil, como un iterador que se ve igual en ambos planes, pero ordered: truesolo en uno; o un número muy diferente de filas estimadas porque una se compiló antes de un cambio de datos importante). También podría ser que se esté tomando un escaneo de orden de asignación, como James describió correctamente en su respuesta.

En cualquier caso, dado que está ejecutando una consulta sin ORDER BY, SQL Server infiere que no le importa el orden, por lo que se apaga y determina la forma más eficiente de devolver las filas (no le importa el orden si no )

Déjame hacer esto muy claro:

Si desea o espera un cierto orden, agregue una cláusula ORDER BY

Esto ha llegado antes:

Y he blogueado al respecto:

Aquí hay una cita de este último que reitera lo que dije para abordar su comentario sobre el uso de una pista de índice en lugar de una ORDER BYcláusula:

Incluso en el caso de un índice insinuado, el índice se usará (si es posible, de lo contrario, se trata de un error en la mayoría de los casos), pero solo porque se use el índice no significa que los resultados se devolverán ordenados por la (s) clave (s) en ese índice Aún necesita un ORDER BYpara garantizar la clasificación por las claves de índice.

Conor Cunningham, un tipo bastante inteligente, directamente responsable de gran parte de lo que hace SQL Server cuando procesa una consulta por usted, también ha publicado un blog al respecto aquí:

Lea un poco y luego agregue una ORDER BYcláusula a sus consultas antes de quejarse de una ordenación diferente o inesperada.

Aaron Bertrand
fuente