Orden de almacenamiento vs orden de resultados


8

Esta es una pregunta derivada del orden de clasificación especificada en la clave principal, pero la clasificación se ejecuta en SELECT .

@Catcall dice esto sobre el tema del orden de almacenamiento (índice agrupado) y el orden de salida

Mucha gente cree que un índice agrupado garantiza un orden de clasificación en la salida. Pero eso no es lo que hace; garantiza una orden de almacenamiento en disco. Ver, por ejemplo, esta publicación de blog .

He leído la publicación de blog de Hugo Kornelis y entiendo que un índice no garantiza que el servidor SQL lea los registros en un orden específico. Sin embargo, ¿me cuesta aceptar que no puedo asumir esto para mi situación?

CREATE TABLE [dbo].[SensorValues](
  [DeviceId] [int] NOT NULL,
  [SensorId] [int] NOT NULL,
  [SensorValue] [int] NOT NULL,
  [Date] [int] NOT NULL,
CONSTRAINT [PK_SensorValues] PRIMARY KEY CLUSTERED 
(
  [DeviceId] ASC,
  [SensorId] ASC,
  [Date] DESC
) WITH (
    FILLFACTOR=75,
    DATA_COMPRESSION = PAGE,
    PAD_INDEX = OFF,
    STATISTICS_NORECOMPUTE = OFF,
    SORT_IN_TEMPDB = OFF,
    IGNORE_DUP_KEY = OFF,
    ONLINE = OFF,
    ALLOW_ROW_LOCKS = ON,
    ALLOW_PAGE_LOCKS = ON)
  ON [MyPartitioningScheme]([Date])

Mi consulta original fue esta:

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010
  ORDER BY Date DESC

Pero sugiero que también podría usar este (lea a continuación para obtener mi explicación):

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010

Como puede ver, las filas de mi tabla son pequeñas (16bytes) y solo tengo un índice, un clúster. En mi escenario, la tabla consta de 100.000.000 registros en este momento (y esto probablemente aumentará diez veces).

Cuando el servidor de bases de datos consulta esta tabla, tiene dos formas de encontrar mis filas, o busca la clave primaria y, por lo tanto, lee y devuelve mis valores en desc. orden de fecha, o tiene que hacer un escaneo completo de la tabla. Mi conclusión es que una exploración completa de la tabla en todos esos registros será demasiado lenta y, por lo tanto, el servidor de la base de datos siempre buscará la tabla a través de su clave principal y, por lo tanto, devolverá los valores ordenados porDate DESC


2
¿Por qué quieres poder confiar tanto en esta suposición? ¿Por qué no te pones una ORDER BYallí y sabes que puedes confiar en ella? Ver # 3 aquí
Aaron Bertrand

Por 2 razones, curiosidad y porque la ORDER BYcláusula es un gran éxito para mí (lea la otra pregunta para obtener más información). Tengo una solución que funciona por ahora, pero no se mantendrá cuando y si mi tráfico aumenta.
m__

1
ORDER BY no debería ser un éxito en el rendimiento si confía en el orden que está viendo sin el orden de - eso no tiene sentido para mí.
Aaron Bertrand

44
Lo único que garantiza el orden del conjunto de resultados es una ORDER BYcláusula en su consulta. Esto es cierto para SQL Server , Oracle , MySQL y cualquier otro RDBMS que se te ocurra. Pruebe cualquier otra cosa y se está preparando para una taza sorpresa de FALLA.
Nick Chammas

Respuestas:


15

Voy a tratar de explicar por qué usted debe no hacer eso, por las que debe Nunca asumir que un subproducto de SQL devolverá un conjunto de resultados en un orden específico, a menos que se especifique lo tanto, lo índices - agrupados o no agrupados, los árboles B o R-Trees o kd-trees o fractal-trees o cualquier otro índice exótico que esté utilizando un DBMS.


Su consulta original le dice al DBMS que busque en la SensorValuestabla, encuentre filas que coincidan con las 3 condiciones, ordene esas filas Datedescendiendo, mantenga solo la primera fila de esas y, finalmente, seleccione y devuelva solo la SensorValuecolumna.

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010
  ORDER BY Date DESC ;

Estas son órdenes muy específicas que le ha dado al DBMS y el resultado probablemente será el mismo cada vez que ejecute la consulta (existe la posibilidad de que no lo sea, si tiene más de una fila que coincida con las condiciones y tenga las mismas max Datepero diferente, SensorValuepero supongamos para el resto de la conversación que no existen tales filas en su tabla).

¿El DBMS tiene que hacer esto, para ejecutar esta consulta, exactamente como la describí anteriormente? No, por supuesto que no, y lo sabes. Es posible que no lea la tabla, sino que lea desde un índice. O puede usar dos índices si cree que es mejor (más rápido). O tres O puede usar un resultado en caché (no SQL Server sino otros resultados de consulta de caché DBMS). O puede usar la ejecución paralela una vez y no la próxima vez que se ejecute. O ... (agregue cualquier otra característica que afecte la ejecución y los planes de ejecución).

Sin embargo, lo que está garantizado es que devolverá exactamente el mismo resultado, cada vez que lo ejecute, siempre que no se inserten, eliminen o actualicen filas.


Ahora veamos qué dice tu sugerencia:

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010 ;

Esta consulta le dice al DBMS que busque en la SensorValuestabla, busque filas que coincidan con las 3 condiciones, ordene esas filas Datedescendiendo , no se preocupe por el orden, mantenga solo una fila y, finalmente, seleccione y devuelva solo la SensorValuecolumna.

Entonces, básicamente dice lo mismo que el primero, excepto que dice que solo desea un resultado que coincida con las condiciones y no le importa cuál .

Ahora, ¿podemos suponer que dará siempre el mismo resultado debido al índice agrupado?
- Si usa este índice agrupado cada vez, sí.

¿Pero lo usará?
- No.

Por qué no?
- Porque puede. El optimizador de consultas es libre de elegir una ruta de ejecución cada vez que ejecuta una instrucción. Cualquiera sea el camino que considere adecuado en ese momento para esa declaración.

¿Pero no está usando el índice agrupado la mejor / más rápida forma de obtener resultados?
- No, no siempre. Puede ser la primera vez que ejecute la consulta. La segunda vez, puede usar un resultado en caché (si el DBMS tiene esa característica, no SQL Server * ). La milésima vez que el resultado puede haberse eliminado de la memoria caché y puede existir otro resultado allí. Digamos que había ejecutado esta consulta justo antes:

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010
  ORDER BY Date ASC ;         --- Notice the `ASC` here

y el resultado en caché (de la consulta anterior) es otro, diferente, que aún coincide con sus condiciones, pero no es el primero en su pedido (deseado). Y le ha dicho al DBMS que no se preocupe por el pedido.

OK, ¿entonces solo el caché puede afectar esto?
- No, muchas otras cosas también.

  • otros índices fueron considerados, en ese momento por el DBMS como mejores para esta consulta.
  • un desarrollador cambió o eliminó por completo este índice agrupado que tenía.
  • usted o algún otro desarrollador agregó otro índice que el optimizador decidió que es más eficiente de usar que el CI.
  • actualizó a una nueva versión y el nuevo optimizador tiene un error menor o un cambio en la clasificación y la elección de los planes de ejecución.
  • Se actualizaron las estadísticas.
  • La ejecución paralela fue elegida en su lugar.

*: SQL Server no almacena en caché los resultados de las consultas, pero Enterprise Edition tiene una función de Análisis avanzado que es similar en el sentido de que puede obtener resultados diferentes debido a consultas simultáneas. Sin embargo, no estoy seguro exactamente cuándo esto entra en acción (Gracias a Martin Smith por la propina).


Espero que esté convencido de que nunca debe confiar en que una consulta SQL devolverá resultados en un orden específico, a menos que así lo especifique. Y nunca use TOP (n)sin ORDER BY, a menos que, por supuesto, solo quiera n filas en el resultado y no le importe cuáles se devuelven.


2
SQL Server Enterprise Edition tiene una función de escaneo avanzado que es similar en el sentido de que puede obtener resultados diferentes debido a consultas concurrentes. Sin embargo, no estoy seguro exactamente cuando esto entra en acción.
Martin Smith

1
Otra cosa que potencialmente "aleatoriza" el orden del conjunto de resultados (incluso si la consulta aparentemente está dirigida por un índice ordenado) es el paralelismo. Vi que una aplicación que había estado ejecutando felizmente SQL roto comienza a comportarse mal después de habilitar el paralelismo automático (no SQL Server, pero supongo que eso podría aplicarse también allí).
Mat
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.