Pregunta

¿Qué puedo hacer para mejorar el rendimiento de las consultas de una consulta de Oracle sin crear índices?

Aquí está la consulta que intento ejecutar más rápido:

SELECT c.ClaimNumber, a.ItemDate, c.DTN, b.FilePath
FROM items a,
itempages b,
keygroupdata c
WHERE a.ItemType IN (112,115,189,241)
AND a.ItemNum = b.ItemNum
AND b.ItemNum = c.ItemNum
ORDER BY a.DateStored DESC

Ninguna de estas columnas está indexada y cada una de las tablas contiene millones de registros. No hace falta decir que la consulta lleva más de 3 minutos y medio. Esta es una base de datos de terceros en un entorno de producción y no se me permite crear ningún índice, por lo que cualquier mejora de rendimiento debería realizarse en la propia consulta.

¡Gracias!

¿Fue útil?

Solución

Primero reescribiría la consulta para ser el estándar ANSI:

SELECT c.ClaimNumber, a.ItemDate, c.DTN, b.FilePath
FROM items a
INNER JOIN itempages b ON b.ItemNum = a.ItemNum
INNER JOIN keygroupdata c ON c.ItemNum = b.ItemNum
WHERE a.ItemType IN (112,115,189,241)
ORDER BY a.DateStored DESC

Esto facilita la lectura y la comprensión de lo que está sucediendo. También le ayuda a no cometer errores (es decir, la unión cruzada) que pueden causar problemas realmente grandes. Luego obtendría el plan Explain para ver qué está haciendo el DBMS con esa consulta. ¿Está tratando de usar algunos índices? ¿Está uniendo las tablas correctamente?

Luego revisaría las tablas con las que estoy trabajando para ver si hay algún índice que ya exista y que pueda estar usando para que mi consulta sea más rápida. Finalmente, como todos los demás han sugerido, eliminaría la cláusula Ordenar por y simplemente lo haría en el código.

Otros consejos

Pida a la tercera parte que indexe sus columnas de unión, ¡como deberían haber hecho en primer lugar! Sin índices, Oracle no tiene nada más que ir a la fuerza bruta.

Es posible que desee intentar crear una vista materializada en cualquiera de esas tablas. Luego, puede crear un índice en la vista materializada que ayudará a acelerar la consulta (que luego sería consultar la vista materializada en lugar de la tabla sin procesar).

Por supuesto, si su tabla subyacente se actualiza, su vista y los índices deberán actualizarse.

Primero, mira el plan de ejecución. ¿Refleja con precisión el número de filas que se recuperarán en cada etapa de la ejecución de la consulta? ¿Qué tan selectivo es el predicado "a.ItemType IN (112,115,189,241)"? ¿El plan de ejecución muestra algún uso del espacio de disco temporal para uniones o clasificaciones?

En realidad, quizás pueda modificar la pregunta para incluir el plan de ejecución.

También asegúrese de no tener las combinaciones hash deshabilitadas, lo que a veces es el caso en los sistemas sintonizados con OLTP, ya que son la forma más eficiente de equiparar datos en masa en Oracle. Deberían aparecer en el plan de ejecución.

Puede intentar filtrar por tipo de elemento antes de unirse a sus tablas, como se muestra aquí.

Si está ejecutando en Oracle antes de 9i, esto a veces brindaría beneficios sorprendentes.

select 
  c.claimnumber,
  a.itemdate, 
  c.dtn,
  b.filepath
from 
  (
  select itemdate
  from items it
  where it.itemtype in(112,115,189,241)
  ) a
  itempages b,
  keygroupdata c
where a.itemnum = b.itemnum
  and b.itemnum = c.itemnum

También puede intentar agregar las sugerencias / + RULE / o / + ORDERED / para ver qué sucede ... otra vez, particularmente con versiones anteriores, esto a veces dar resultados sorprendentes.

SELECT /*+RULE*/
  c.ClaimNumber, a.ItemDate, c.DTN, b.FilePath
FROM
  items a,
  itempages b,
  keygroupdata c
WHERE a.ItemType IN (112,115,189,241)
  AND a.ItemNum = b.ItemNum
  AND b.ItemNum = c.ItemNum
ORDER BY a.DateStored DESC

Si las entradas de la consulta son constantes o predecibles ( itemType IN (...) ), una alternativa sería ejecutar la consulta una o dos veces al día y almacenar los resultados en un local. Tabla, con índices en su caso.

Luego puede hacer la consulta costosa 'fuera de línea' y obtener mejores resultados más rápidos para una consulta interactiva.

¿Es esta una consulta que ejecutas a menudo? Parece que sería del interés del propietario de la base de datos crear los índices que necesita para acelerar esta consulta. ¡Los 3.5 minutos que dedica a ejecutar la consulta deben tener algún impacto en su entorno de producción!

Además, ¿han estado ejecutando estadísticas de actualización en las tablas? Eso podría mejorar el rendimiento, ya que el orden de unión se calcula en función de las estadísticas de las tablas.

Por cierto, ¿qué puedes hacer? ¿Acabo de leer? Si puede crear tablas temporales y colocar índices en ellas, podría considerar hacer copias temporales de la tabla, indexarlas y luego hacer la unión asistida por índice con las copias temporales.

Sé que este hilo es muy antiguo, pero para los motores de búsqueda todavía quería ofrecer una solución alternativa que funcione en Oracle y, dependiendo de los datos, podría ser mucho más rápido.

with a as (
  select 
    * 
  from 
    items 
  where 
    ItemType IN (112,115,189,241)
)
SELECT 
  c.ClaimNumber
  , a.ItemDate
  , c.DTN, b.FilePath
FROM 
  a,
  itempages b,
  keygroupdata c
WHERE 
  a.ItemNum = b.ItemNum
  AND b.ItemNum = c.ItemNum
ORDER BY 
  a.DateStored DESC

También puede probar la sugerencia / * + MATERIALIZE * / en la cláusula WITH .

En realidad, la antigua sintaxis de uniones de oracle me resulta mucho más fácil de leer que ansi sql ^^

Sin indexación, la consulta solo empeorará a medida que aumente el tamaño de la tabla. Dicho esto, intente eliminar el orden por cláusula y haga ese tipo de orden en el lado del cliente.

A veces puede ver un beneficio agregando rutas adicionales para que el optimizador elija agregando elementos que parecen redundantes a la cláusula where.

Por ejemplo, tienes A.ItemNum = B.ItemNum Y B.ItemNum = C.ItemNum. Intente agregar A.ItemNum = C.ItemNum también. Sin embargo, estoy bastante seguro de que el optimizador es lo suficientemente inteligente como para darse cuenta de eso, vale la pena intentarlo.

Dependiendo del tipo de datos de la columna ItemType, puede experimentar una ejecución más rápida utilizando lo siguiente si es un varchar, Oracle hará conversiones implícitas.

SELECT c.ClaimNumber, a.ItemDate, c.DTN, b.FilePath
FROM items a,
itempages b,
keygroupdata c
WHERE ((a.ItemType IN ('112','115','189','241'))
AND (a.ItemNum = b.ItemNum)
AND (b.ItemNum = c.ItemNum))
ORDER BY a.DateStored DESC

¿Se recopilan estadísticas en estas tablas? De lo contrario, la recopilación de estadísticas podría cambiar el plan de ejecución, aunque no necesariamente sería para mejor.

Aparte de eso, mira el plan de ejecución. Puede ver que está uniendo las tablas en un orden no óptimo (por ejemplo, podría estar uniendo b y c antes de unirse a una que tiene la condición de filtro).

Puede usar sugerencias para tratar de afectar las rutas de acceso, orden de combinación o método de combinación.

Actualización : responder al comentario me llevó a esto presentación, que podría ser útil o al menos interesante.

Si dice que no hay índices, ¿significa esto también que no hay claves primarias o externas definidas? Obviamente, el análisis de las tablas y la recopilación de estadísticas son importantes, pero si no existen metadatos como la definición de cómo se deben unir las tablas, entonces Oracle puede elegir una ruta de ejecución deficiente.

En ese caso, utilizar una sugerencia como / * + ORDERED * / puede ser la única opción para que el optimizador elija de forma confiable una buena ruta de ejecución. También puede valer la pena agregar claves foráneas y primarias, pero defínalos como DESACTIVAR y VALIDAR.

Supongo que la utilidad de este comentario depende de hasta dónde llega la aversión a los índices, por lo que YMMV.

Primero cree una vista en esta consulta y luego genere una tabla desde esta vista. También cree un índice en la fecha, haga un trabajo y programelo para la medianoche cuando el sistema esté inactivo.

Bueno, ya que no se pueden crear índices, me aseguraría de que todas las estadísticas estén actualizadas en ese momento, volvería a escribir la consulta de esta manera:

con un como (seleccione / * + MATERIALIZE * / ItemType, ItemNum, DateStored, ItemDate de los elementos donde ItemType (112,115,189,241)) SELECCIONE c.ClaimNumber, a.ItemDate, c.DTN, b.FilePath A partir de una, itempages b, keygroupdata c DONDE a.ItemNum = b.ItemNum Y b.ItemNum = c.ItemNum ORDEN POR UN.

Eliminar el ORDEN POR

realice la ordenación, después de que vuelva a colocar las filas en su aplicación.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top