2010-01-05 15 views
7

Me sale un comportamiento extraño del plan de ejecución de SQL Server (2005).sql server: El número estimado de filas está lejos

NombreTabla: REGISTRO
... contiene alrededor de 1000 filas

  • int Id
  • Nombre varchar (50)

Consulta:

SELECT * 
    FROM (SELECT ROW_NUMBER() OVER (ORDER BY ID DESC) as Row, 
       ID, Name 
      FROM Log) AS LogWithRowNumbers 
WHERE Row >= 1 
    AND Row <= 2 

Se estima el num ber de filas devueltas como 9 (aunque es obvio 2 o menos).
Además, la eliminación de la "fila y < = 2" se incrementará el tiempo de ejecución en alrededor de 5. * ("y Fila < = 2" y "y la fila < = 9999999999999" se comportan de la misma)

tengo estadísticas actualizadas Pero aún así, este comportamiento es extraño. Agregar la fila < 99999999999 hará que la consulta se ejecute más rápido? por qué ?

+0

Vamos chicos, es fácilmente reproducible. ¿Dónde están esos genios de DBA cuando los necesitas? – Faruz

+0

@Faruz: No soy un DBA. Pero la consulta funciona más rápido cuando tiene un único criterio sin Y/O (es decir, ROW = 1). ¿Cómo funciona cuando 'ROW = 1 OR ROW = 2' contra el uso de'> = 'y' <= '. ¿Crea algún índice para la tabla 'Log' internamente? – shahkalpesh

+0

Fila = 1 o fila = 2 estimadas 58 filas devueltas ... No crea un índice interno sino que usa el índice PK (ID). – Faruz

Respuesta

6

No soy experto en el proceso interno de optimización de consultas/trabajos de SQL Server, pero aquí están mis 2 peniques (o centavos, si lo prefiere).

Creo que se debe al uso del valor ROW_NUMBER() dentro de la cláusula WHERE. Como ejemplo, creé una tabla de muestra, con 1000 filas de ID 1 a 1000 (ID como clave principal) como dijiste.

Si usted saca la ROW_NUMBER(), y hacer la consulta sobre la base de la columna ID de la siguiente manera:

Select * FROM 
(
SELECT ID, Name 
FROM Log 
) 
as LogWithRowNumbers 
WHERE ID>=1 and ID<=2 

A continuación se muestra correctamente el número de filas como 2 - como se esperaba realmente.

Ahora, trabajando hacia atrás, agregar en el ROW_NUMBER a la SELECT interna, pero dejan la cláusula WHERE como está, como a continuación:

Select * FROM 
(
SELECT ROW_NUMBER() OVER (ORDER BY ID DESC) AS RowNo, 
ID, Name 
FROM Log 
) 
as LogWithRowNumbers 
WHERE ID>=1 AND ID <=2 

Esto todavía muestra el número de filas como correcta 2.

último , vuelva a establecer la cláusula WHERE para usar RowNo como la columna filtrada en lugar de ID, aquí es cuando el recuento estimado de filas salta a 9.

Por lo tanto, creo que es el uso de la función ROW_NUMBER(), que es filtrado en la cláusula WHERE que es la c ause. Así que me imagino que es porque obviamente hay estadísticas mejores/más precisas disponibles en las columnas de la tabla real que en este valor producido por la función.

Espero que esto al menos proporcione un buen punto de partida, ¡espero que sea útil!

2

AdaTheDev es correcto. La razón por la que ve este comportamiento es porque SQL Server tiene que calcular los números de fila para la tabla antes de poder usarlos en la cláusula where.

Esto debería ser una forma más eficiente de conseguir los mismos resultados:

SELECT TOP(2) ROW_NUMBER() OVER (ORDER BY ID DESC) as Row, 
ID, Name 
FROM Log 
ORDER BY ID DESC 
+0

Entiendo lo que dices, solo que es un ejemplo de una consulta que realizo. Normalmente recupero las filas 1-10, 10-20, etc. El problema es que tengo que hacerlo sin la "Fila <999999" y eso cuesta más – Faruz

Cuestiones relacionadas