2009-01-14 9 views
11

estoy usando una consulta SQL que es similar a la siguiente forma:externa izquierda en el problema de rendimiento dos columnas

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

Y es ya sea demasiado lenta o algo está deadlocking porque se necesitan al menos 4 minutos a regreso. 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 manera de acelerar esto?

ACTUALIZACIÓN: Se hace lo mismo que si me 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 ve que estoy unirse. Desafortunadamente, están en una base de datos sobre la que no tengo control, por lo que no puedo (fácilmente) hacer cambios en la indexación. Me inclino a aceptar que esto es un problema de indexación. Esperaré un poco antes de aceptar una respuesta en caso de que haya alguna forma mágica de sintonizar esta consulta que yo desconozca. De lo contrario, aceptaré una de las respuestas actuales y trataré de encontrar otra forma de hacer lo que quiero hacer. Gracias por la ayuda de todos hasta ahora.

+0

proporcione el plan de ejecución para esta consulta – squadette

Respuesta

16

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á tomando eso en cuenta (como 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 obtiene el mismo problema de rendimiento.

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

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

+0

Que los errores de consulta que no puedo mezclar uniones externas ANSI y uniones externas de estilo antiguo. –

+0

Corregido. Trata eso. – cletus

+1

Con sus consultas originales con WHERE, la base de datos era libre de conducir desde la tabla 2 obteniendo las entradas de la tabla1 donde coincide el período_personal o el período. La consulta original DEBE escanear completamente la tabla1 y funcionará mal si hay un acceso deficiente a la tabla 2 (p. Ej., Ningún índice útil). –

3

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

Si no es así, añadirlos y vuelve a intentarlo.

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

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

+0

Um, la qestion está etiquetada oráculo, así que no creo que esté usando SQL Server. – cletus

+0

Ah :) No vi eso ... No importa ... El plan de ejecución también está disponible en Oracle. Voy a editar la respuesta. –

2

¿Estas tablas tienen índices en las columnas que se unen? Instale el producto gratuito SQLDeveloper de Oracle y úselo para hacer una "explicación" sobre esa consulta y ver si está haciendo escaneos secuenciales de ambas tablas.

5

Creo que debe entender por qué las dos últimas no son la misma consulta que la primera. Si hace 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 unión (la que puede no tener siempre un registro para coincidir con la primera tabla), entonces ha cambiado efectivamente la unión a una unión interna.Hay una excepción a esta y es que si se hace referencia a algo así 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, solicitando el registro que no tienen un registro en la segunda tabla. Pero aparte de este caso especial, está cambiando la combinación izquierda a una combinación interna si hace referencia a un campo en la tabla 2 en la cláusula where.

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

2

En una combinación a la izquierda estaría escaneando table1 para cada combinación única de (person_uid, period) y luego buscando en table2 todos los registros correspondientes allí. Si la tabla 2 no tiene un índice apropiado, esto puede implicar el escaneo de 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 tabla tabla tabla2 así como mesa1.

Como dice que no puede cambiar los índices, debe cambiar la consulta. Por lo que yo puedo decir, sólo 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 escanea tabla2 para cada combinación única de (person_uid, período), pero hacen uso de índices en la Tabla 1. (A diferencia de escanear table1 y hacer uso de índices en table2, que era lo que esperaba de su consulta.)

Si table1 no tiene los índices apropiados, sin embargo, es muy poco probable que vea una mejora en el rendimiento en todos ...

Dems.

4

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

Mire el plan de ejecución para 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

+1

@Dave Costa: ¡Absolutamente! Use la traza de Oracle para descubrir el plan de ejecución y lo que Oracle está esperando. En ausencia de eso, todo el mundo está adivinando. – spencer7593

+0

http://download.oracle.com/docs/cd/B28359_01/server.111/b28274/sqltrace.htm – spencer7593

0

En una de las actualizaciones de la OP indica que él es en realidad la consulta de puntos de vista no mesas. En este caso, el rendimiento podría incrementarse al consultar directamente las tablas que necesita, especialmente si las vistas son complejas y unirse a muchas otras tablas que no contienen la información que necesita o son vistas que llaman a vistas.

0

La sintaxis de unión ANSI proporciona una distinción muy clara entre las condiciones JOIN y los predicados FILTER; esto es muy importante al escribir uniones externas. Utilizando las tablas de EMP/Dept, mirar los resultados de los dos exteriores siguiente une

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 luego se vuelven a agregar como parte de la combinación externa. No es necesariamente incorrecto, pero ¿es esa la consulta que realmente pediste? A menudo son los resultados mostrados en Q2 los requeridos, donde el filtro se aplica después de la unión (externa).

También existe una implicación en el rendimiento, para grandes conjuntos de datos.En muchos casos, unirse al constante debe ser resuelto internamente por el optimizador creando una vista lateral, que normalmente solo puede optimizarse mediante una unión de bucle anidado en lugar de una combinación hash

Para desarrolladores que están familiarizados con Oracle sintaxis de combinación externa, la consulta probablemente habría sido escrita 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 Q2 anteriormente.

Por lo tanto, en resumen, es extremadamente importante que comprenda las diferencias entre la cláusula JOIN y la cláusula WHERE al escribir uniones externas ANSI.

Cuestiones relacionadas