2008-12-09 12 views
50

Tengo 2 tablas (A y B) con las mismas teclas principales. Quiero seleccionar toda la fila que están en A y no en B. Las siguientes obras:Mysql selecciona dónde no está en la tabla

select * from A where not exists (select * from B where A.pk=B.pk); 

sin embargo, parece bastante malo (~ 2 segundos en sólo 100k filas en A y en B 3-10k menos)

¿Hay una manera mejor de ejecutar esto? Tal vez como una izquierda unirse?

select * from A left join B on A.x=B.y where B.y is null; 

En mis datos esto parece funcionar un poco más rápido (~ 10%) pero ¿qué pasa en general?

+0

Qué quiere decir que tiene 100k filas de la tabla A y 100k filas en la tabla B? O simplemente alrededor de 300 filas en cada tabla, lo que significa 100.000 escaneos de fila (o, con suerte, escaneos de índice). – ChrisInEdmonton

Respuesta

35

Utilizo consultas en el formato de su segundo ejemplo. Una unión suele ser más escalable que una subconsulta correlacionada.

50

Creo que su última declaración es la mejor. También puede probar

SELECT A.*  
from A left join B on 
    A.x = B.y 
    where B.y is null 
+1

Eso no tiene ningún sentido. Cuando B.y es nulo, A.x = B.y nunca será verdadero. Obtendrá todas las filas de A, no solo aquellas que no tienen una fila coincidente en B. –

+2

@Bill y sin embargo, ¡funciona! Además, es exactamente lo mismo que la segunda declaración mencionada anteriormente. –

+2

Cambié y hacia dónde. – hamstar

2

También uso uniones izquierdas con un criterio de tipo "where table2.id is null".

Sin duda, parece ser más eficiente que la opción de consulta anidada.

2

Las uniones son generalmente más rápidas (en MySQL), pero también debería considerar su esquema de indexación si nota que todavía se mueve lentamente. En general, cualquier configuración de campo como una clave externa (usando INNODB) ya tendrá un conjunto de índices. Si está utilizando MYISAM, asegúrese de que todas las columnas de la declaración ON estén indexadas, y considere agregar también columnas en la cláusula WHERE al final del índice, para convertirlo en un índice de cobertura. Esto permite que el motor tenga acceso a todos los datos necesarios en el índice, eliminando la necesidad de hacer un segundo viaje de ida y vuelta a los datos originales. Tenga en cuenta que esto afectará la velocidad de las inserciones/actualizaciones/eliminaciones, pero puede aumentar significativamente la velocidad de la consulta.

+0

En realidad, Raul, su edición lo hace parecer que debería crear un índice separado para las columnas en la cláusula WHERE.Para mayor claridad, quise agregar las columnas al índice (que cubre el índice), por lo que el motor no tendría que hacer un viaje de ida y vuelta a los datos base para la cláusula WHERE. Disculpas por no ser claro. – Chosun

-2

Esto me ayudó mucho. Joins son siempre más rápido que subconsultas para dar resultados:

SELECT tbl1.id FROM tbl1 t1 
LEFT OUTER JOIN tbl2 t2 ON t1.id = t2.id 
WHERE t1.id>=100 AND t2.id IS NULL ; 
Cuestiones relacionadas