Pregunta

Estoy usando una consulta SQL que es similar a la siguiente forma:

SELECT col1, col2
FROM table1
LEFT OUTER JOIN table2
ON table1.person_uid = table2.person_uid
AND table1.period = table2.period

Y es demasiado lento o algo está estancado porque tarda al menos 4 minutos en volver. Si tuviera que cambiarlo a esto:

SELECT col1, col2
FROM table1
LEFT OUTER JOIN table2
ON table1.person_uid = table2.person_uid
WHERE table1.period = table2.period

entonces funciona bien (aunque no devuelve el número correcto de columnas). ¿Hay alguna forma de acelerar esto?

ACTUALIZACIÓN : hace lo mismo si cambio las dos últimas líneas de la última consulta:

SELECT col1, col2
FROM table1
LEFT OUTER JOIN table2
ON table1.period = table2.period
WHERE table1.person_uid = table2.person_uid

ACTUALIZACIÓN 2: Estas son en realidad vistas a las que me estoy uniendo. Desafortunadamente, están en una base de datos sobre la que no tengo control, por lo que no puedo (fácilmente) realizar ningún cambio en la indexación. Sin embargo, me inclino a aceptar que este es un problema de indexación. Esperaré un poco antes de aceptar una respuesta en caso de que haya alguna forma mágica de ajustar esta consulta que no conozco. De lo contrario, aceptaré una de las respuestas actuales e intentaré encontrar otra forma de hacer lo que quiero hacer. Gracias por la ayuda de todos hasta ahora.

¿Fue útil?

Solución

Tenga en cuenta que las declaraciones 2 y 3 son diferentes a la primera.

¿Cómo? Bueno, estás haciendo una combinación externa izquierda y tu cláusula WHERE no está teniendo eso en cuenta (como lo hace la cláusula ON). Como mínimo, intente:

SELECT col1, col2
FROM table1, table2
WHERE table1.person_uid = table2.person_uid (+)
AND table1.period = table2.period (+)

y vea si tiene el mismo problema de rendimiento.

¿Qué índices tiene en estas tablas? ¿Esta relación está definida por una restricción de clave externa?

Lo que probablemente necesite es un índice compuesto en person_uid y period (en ambas tablas).

Otros consejos

Creo que debe comprender por qué las dos últimas no son la misma consulta que la primera. Si realiza una combinación izquierda y luego agrega una cláusula where que hace referencia a un campo en la tabla en el lado derecho de la combinación (el que puede no tener siempre un registro que coincida con la primera tabla), entonces ha cambiado efectivamente la combinación a Una unión interior. Hay una excepción a esto y es si hace referencia a algo como

SELECT col1, col2
FROM table1
LEFT OUTER JOIN table2
ON table1.person_uid = table2.person_uid
WHERE table2.person_uid is null

En este caso, solicita el registro que no tiene un registro en la segunda tabla. Pero aparte de este caso especial, está cambiando la unión izquierda a una unión interna si hace referencia a un campo en la tabla2 en la cláusula where.

Si su consulta no es lo suficientemente rápida, miraría su indexación.

Cualquier cosa que alguien le diga en base a la información que proporcionó es una suposición.

Mire el plan de ejecución de la consulta. Si no ve una razón para la lentitud en el plan, publique el plan aquí.

http://download.oracle .com / docs / cd / B28359_01 / server.111 / b28274 / ex_plan.htm # PFGRF009

¿Tiene índices de cobertura en person_uid y period para ambas tablas?

Si no, agréguelos e intente nuevamente.

Eche un vistazo al plan de ejecución y vea qué está haciendo realmente la consulta.

También: ¿Cuáles son los tipos de datos de los campos? ¿Son iguales en ambas tablas? Un reparto implícito realmente puede ralentizar las cosas.

¿Estas tablas tienen índices en las columnas a las que se une? Instale el producto SQLDeveloper gratuito de Oracle y úselo para hacer una " explicar " en esa consulta y vea si está haciendo exploraciones secuenciales de ambas tablas.

En una unión izquierda, estaría escaneando la tabla1 para cada combinación única de (person_uid, punto) y luego buscaría en la tabla2 todos los registros correspondientes allí. Si table2 no tiene un índice apropiado, esto puede implicar escanear toda esa tabla también.

Mi mejor conjetura, sin ver un plan de ejecución, es que la primera consulta (la única que parece ser correcta) es tener que escanear la tabla tabla2 así como la tabla1.

Como dice que no puede cambiar los índices, debe cambiar la consulta. Por lo que puedo decir, solo hay una alternativa realista ...

SELECT
   col1, col2
FROM
   table2
FULL OUTER JOIN
   table1
      ON table1.person_uid = table2.person_uid
      AND table1.period = table2.period
WHERE
   table1.person_uid IS NOT NULL

La esperanza aquí es que escanee la tabla2 para cada combinación única de (person_uid, punto), pero haga uso de los índices en la tabla1. (A diferencia de escanear table1 y hacer uso de índices en table2, que era lo que esperaba de su consulta).

Si la tabla 1 no tiene los índices apropiados, sin embargo, es muy poco probable que vea alguna mejora en el rendimiento ...

Dems.

En una de las actualizaciones, el OP indica que en realidad está consultando vistas, no tablas. En este caso, el rendimiento podría incrementarse al consultar directamente las tablas que necesita, especialmente si las vistas son complejas y se unen a muchas otras tablas que no contienen la información que necesita o son vistas que llaman vistas.

La sintaxis de unión ANSI proporciona una distinción muy clara entre condiciones JOIN y predicados FILTER; Esto es muy importante cuando se escriben combinaciones externas. Usando las tablas emp / dept, mira los resultados de las siguientes dos combinaciones externas

Q1

SELECT dname, d.deptno, e.ename, e.mgr, d.loc
FROM dept d
LEFT OUTER JOIN emp e
on  d.deptno = e.deptno
and loc in ('NEW YORK','BOSTON' )
;

DNAME              DEPTNO ENAME             MGR LOC
-------------- ---------- ---------- ---------- -------------
ACCOUNTING             10 CLARK            7839 NEW YORK
ACCOUNTING             10 KING                  NEW YORK
ACCOUNTING             10 MILLER           7782 NEW YORK
RESEARCH               20                       DALLAS
SALES                  30                       CHICAGO
OPERATIONS             40                       BOSTON

====

Q2
SELECT dname, d.deptno, e.ename, e.mgr, d.loc
FROM dept d
LEFT OUTER JOIN emp e
on  d.deptno = e.deptno
where loc in ('NEW YORK','BOSTON' )
;

DNAME              DEPTNO ENAME             MGR LOC
-------------- ---------- ---------- ---------- -------------
ACCOUNTING             10 CLARK            7839 NEW YORK
ACCOUNTING             10 KING                  NEW YORK
ACCOUNTING             10 MILLER           7782 NEW YORK
OPERATIONS             40                       BOSTON

El primer ejemplo, Q1 muestra es un ejemplo de "unirse en una constante". Esencialmente, la condición del filtro se aplica antes de realizar la unión externa. Por lo tanto, elimina las filas, que posteriormente se agregan nuevamente como parte de la unión externa. No es necesariamente incorrecto, pero ¿es esa la consulta que realmente solicitó? A menudo, se requieren los resultados que se muestran en el segundo trimestre, donde el filtro se aplica después de la unión (externa).

También hay una implicación de rendimiento también, para grandes conjuntos de datos. En muchos casos, el optimizador debe resolver internamente la unión en una constante mediante la creación de una vista lateral, que generalmente solo se puede optimizar a través de una unión de bucle anidado en lugar de una unión hash

Para los desarrolladores que están familiarizados con la sintaxis de combinación externa de Oracle, la consulta probablemente se habría escrito como

SELECT dname, d.deptno, e.ename, e.mgr, d.loc
FROM dept d
        ,emp e
where  d.deptno = e.deptno(+)
and loc in ('NEW YORK','BOSTON' )

Esta consulta es semánticamente equivalente a la Q2 anterior.

Entonces, en resumen, es extremadamente importante que comprenda la diferencia entre la cláusula JOIN y la cláusula WHERE al escribir uniones externas ANSI.

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