2009-09-11 29 views
7

Tengo una base de datos de oráculos poblada con un millón de registros. registros que estoy tratando de escribir una consulta SQL que devuelve el primer 'n" Ordenada (dicen 100 registros) de la base de datos basada en ciertas condiciones.¿Cómo seleccionar los primeros registros 'N' de una base de datos que contiene millones de registros?

SELECT * 
FROM myTable 
Where SIZE > 2000 
ORDER BY NAME DESC 

A continuación, mediante programación seleccionar N primeros registros.

El problema con este enfoque es:

  • los resultados de la consulta en medio millón de registros y "Ordenar por nombre" causas todos los registros que se clasifican en NOMBRE en el orden descendente esta clasificación está tomando mucho tiempo (casi.. 30-40 segundos ds. Si omito ORDER BY, solo demora 1 segundo).
  • Después del género Estoy interesado en solo primeros N (100) registros. Entonces la clasificación de registros completos no es útil.

Mis preguntas son:

  1. ¿Es posible especificar la 'N' en propia consulta? (por lo que la ordenación se aplica solo a N registros y la consulta se vuelve más rápida).
  2. Cualquier forma mejor en SQL para mejorar la consulta para ordenar solo N elementos y devolver en tiempo rápido .

Respuesta

19

Si su propósito es encontrar 100 filas aleatorias y ordenarlas luego, entonces Lasse's solution es correcto. Si como creo que usted quiere que los primeros 100 registros ordenados por su nombre mientras se descartan los otros le construiría una consulta como esta:

SELECT * 
    FROM (SELECT * 
      FROM myTable 
     WHERE SIZE > 2000 ORDER BY NAME DESC) 
WHERE ROWNUM <= 100 

El optimizador entenderá que se trata de una consulta TOP-N y será capaz de utilizar un índice en NAME.No tendrá que ordenar todo el conjunto de resultados, solo comenzará al final del índice y lo leerá hacia atrás y parará después de 100 filas.

También podría agregar una sugerencia a su consulta original para que el optimizador comprenda que usted está interesado en las primeras filas solamente. Esto probablemente generará una ruta de acceso similar:

SELECT /*+ FIRST_ROWS*/* FROM myTable WHERE SIZE > 2000 ORDER BY NAME DESC 

Editar:AND rownum <= 100 sólo añadir a la consulta no funcionará ya que en Oracle rownum se atribuye antes clasificación: es por eso que usted tiene que utilizar una subconsulta . Sin la subconsulta, Oracle seleccionará 100 filas aleatorias y luego las clasificará.

+0

¡Es increíble, funciona! – Oliver

4

Añadir este:

AND rownum <= 100 

a su cláusula WHERE.

Sin embargo, esto no hará lo que está pidiendo.

Si desea seleccionar 100 filas aleatorias, ordenarlas y luego devolverlas, primero deberá formular una consulta sin ORDER BY, luego limitarla a 100 filas, luego seleccionarla y ordenarla.

Esto podría trabajo, pero por desgracia no tengo un servidor Oracle disponible para la prueba:

SELECT * 
FROM (
    SELECT * 
    FROM myTable 
    WHERE SIZE > 2000 
     AND rownum <= 100 
    ) x 
ORDER BY NAME DESC 

Pero tenga en cuenta la parte "al azar" no, usted está diciendo "dame 100 filas con TAMAÑO> 2000, no me importa qué 100 ".

¿Eso es realmente lo que quieres?

Y no, en realidad no obtendrá un resultado aleatorio, en el sentido de que cambiará cada vez que consulte el servidor, pero está a merced del optimizador de consultas. Si la carga de datos y las estadísticas de índice para esa tabla cambian con el tiempo, en algún momento puede obtener datos diferentes a los que obtuvo en la consulta anterior.

+0

Gracias por la respuesta. Mi consulta no es obtener 100 aleatorios. Quiero obtener los primeros 100 registros ordenados. Por ejemplo: si los registros son 1,5,8,2,14,3,6,7. Y si quiero 3 registros, la respuesta sería (1,2,3) –

+2

Luego, * do * quiere que se clasifiquen primero, y si ordenar las millones de filas lleva mucho tiempo, eso no ayudará mucho. Todo lo que debes hacer es evitar recuperar todas las filas en la red, el género todavía tiene que ejecutarse. –

+1

Sin embargo, Oracle es lo suficientemente inteligente como para mantener los primeros 100 resultados. Si la siguiente fila está fuera de ese 100, la descarta. De esta forma, no tiene que ordenar todo. Esto es O (n) en lugar de O (n log n) –

5

This muestra cómo seleccionar las N filas superiores según su versión de Oracle.

De Oracle 9i en adelante, el RANK() y DENSE_RANK() pueden ser utilizados para determinar las filas TOP N. Ejemplos:

Obtener los 10 primeros empleados en función de su salario

Ename SELECT, Sal FROM (SELECT ename, sal, RANK() OVER (ORDER BY Sal DESC) sal_rank énfasis DE) Cuando sal_rank < = 10;

seleccionar a los empleados haciendo los 10 salarios más altos

Ename SELECT, Sal desde (SELECT ename, sal, DENSE_RANK() OVER (ORDEN por Sal DESC) sal_dense_rank énfasis DE) DONDE sal_dense_rank < = 10 ;

La diferencia entre los dos se explica here

0

Su problema es que la especie se está haciendo cada vez que se ejecuta la consulta. Puede eliminar la operación de clasificación utilizando un índice; el optimizador puede usar un índice para eliminar una operación de clasificación, si la columna ordenada se declara NOT NULL.

(Si la columna es anulable, aún es posible, ya sea (a) agregando un predicado NOT NULL a la consulta, o (b) agregando un índice basado en funciones y modificando la cláusula ORDER BY según corresponda).

0

Solo como referencia, en Oracle 12c, esta tarea puede realizarse usando la cláusula FETCH. Puede ver here para obtener ejemplos y enlaces de referencia adicionales con respecto a este asunto.

Cuestiones relacionadas