2011-06-13 8 views
7

Estoy tratando de obtener la diferencia entre dos tablas casi idénticas en postgresql. La consulta actual Me postulo es:Postgresql UNION toma 10 veces más tiempo que ejecutar las consultas individuales

SELECT * FROM tableA EXCEPT SELECT * FROM tableB; 

y

SELECT * FROM tableB EXCEPT SELECT * FROM tableA; 

Cada una de las consultas anteriores dura aproximadamente 2 minutos para correr (Su una gran mesa)

quería combinar los dos consultas con la esperanza de ahorrar tiempo, así que probé:

SELECT * FROM tableA EXCEPT SELECT * FROM tableB 
UNION 
SELECT * FROM tableB EXCEPT SELECT * FROM tableA; 

Y mientras funciona, se tarda 20 minutos en ejecutar !!! Supongo que tomaría como mucho 4 minutos, la cantidad de tiempo para ejecutar cada consulta individualmente.

¿Hay algún trabajo adicional que UNION esté haciendo que lo lleve tanto tiempo? ¿O hay alguna manera de acelerarlo (con o sin UNIÓN)?

ACTUALIZACIÓN: Ejecutar la consulta con UNION ALL toma 15 minutos, casi 4 veces más que ejecutar cada uno por su cuenta, ¿Estoy en lo cierto al decir que UNION (todo) no va a acelerar esto en absoluto?

+0

¿Habrá duplicados en 'tableA' o' tableB' solo que deben omitirse? De lo contrario, intente 'UNION ALL'. –

+0

@ScrumMeister: No he pensado en este antes. ¿Quita la unión los duplicados que provienen de una sola tabla? Pensé que solo eliminaba duplicados entre las dos tablas unificadas. Puede que tenga que investigar eso. – RThomas

+0

¿Se puede publicar la salida de 'EXPLAIN ANALYZE'? –

Respuesta

11

Con respecto a su pregunta de "trabajo extra". Sí. Union no solo combina las dos consultas sino que también procesa y elimina los duplicados. Es lo mismo que usar una declaración distinta.

Por esta razón, especialmente combinado con sus declaraciones excepto "union all" probablemente sea más rápido.

leer más aquí: http://www.postgresql.org/files/documentation/books/aw_pgsql/node80.html

+0

Acabo de ejecutar "SELECT * FROM tableA EXCEPT SELECT * FROM tableB UNION ALL SELECT * FROM tableB EXCEPT SELECT * FROM tableA;" Tardó 15 minutos, por lo que aún no es tan rápido como ejecutar las dos consultas por separado. – lanrat

+0

Estoy seleccionando esta como la respuesta correcta, pero parece que ejecutar las consultas por separado la acelera. – lanrat

+0

@RThomas al agregar 'union all' agrega el valor redundante ¿qué pasa si quiero los valores distintos? – Lokesh

3

Además de combinar los resultados de la primera y la segunda consulta, UNION por defecto elimina también los registros duplicados. (ver http://www.postgresql.org/docs/8.1/static/sql-select.html). El trabajo extra involucrado en la verificación de registros duplicados entre las dos consultas es probablemente responsable del tiempo extra. En esta situación, no debe haber registros duplicados, por lo que se puede evitar el trabajo adicional en busca de duplicados especificando UNION ALL.

SELECT * FROM tableA EXCEPT SELECT * FROM tableB 
UNION ALL 
SELECT * FROM tableB EXCEPT SELECT * FROM tableA; 
+0

Parece que fui un poco lento en obtener mi respuesta mecanografiada. Felicitaciones a lazyDBA – dave

-2

Usted podría utilizar tablaA combinación externa completa TableB, lo que daría lo que quiere (con un propre unirse a condición) con sólo 1 mesa de exploración, probablemente sería más rápido que las 2 consultas anteriores.

Publique más información por favor.

2

No creo que el código arroje los resultados que usted desea. Prefiero pensar que desea hacer esto:

SELECT * 
    FROM (
     SELECT * FROM tableA 
     EXCEPT 
     SELECT * FROM tableB 
     ) AS T1 
UNION 
SELECT * 
    FROM (
     SELECT * FROM tableB 
     EXCEPT 
     SELECT * FROM tableA 
     ) AS T2; 

En otras palabras, desea el conjunto de miembros mutuamente excluyentes.Si es así, es necesario leer sobre la precedencia de operadores relacionales en SQL;) Y cuando usted tiene, usted puede darse cuenta de lo anterior puede ser racionalizada a:

SELECT * FROM tableA 
UNION 
SELECT * FROM tableB 
EXCEPT 
SELECT * FROM tableA 
INTERSECT 
SELECT * FROM tableB; 

Fwiw, el uso de subconsultas (tablas derivadas T1 y T2) para mostrar de forma explícita (lo que sería de otra manera implícita) precedencia de los operadores relacionales, su búsqueda original es la siguiente:

SELECT * 
    FROM (
     SELECT * 
      FROM (
       SELECT * 
        FROM tableA 
       EXCEPT 
       SELECT * 
        FROM tableB 
       ) AS T2 
     UNION 
     SELECT * 
      FROM tableB 
     ) AS T1 
EXCEPT 
SELECT * 
    FROM tableA; 

lo anterior se puede relationalised a:

SELECT * 
    FROM tableB 
EXCEPT 
SELECT * 
    FROM tableA; 

... y no creo lo que se pretende.

+0

¡Gracias por la explicación! Ejecuté la primera consulta que me proporcionó, pero todavía lleva mucho más tiempo que ejecutar las dos consultas individuales. Las dos consultas que estoy ejecutando son exactamente lo que quiero; Solo lo quiero más rápido :). La segunda consulta que proporcionó tomó más de 1 hora, por lo que la detuve (donde todas las demás estuvieron por debajo de 10 minutos) – lanrat

Cuestiones relacionadas