Cómo encontrar filas en una tabla que no tengan una fila correspondiente en otra tabla
-
06-07-2019 - |
Pregunta
Tengo una relación 1: 1 entre dos tablas. Quiero encontrar todas las filas en la tabla A que no tienen una fila correspondiente en la tabla B. Uso esta consulta:
SELECT id
FROM tableA
WHERE id NOT IN (SELECT id
FROM tableB)
ORDER BY id desc
id es la clave principal en ambas tablas. Además de los índices de clave principal, también tengo un índice en la tabla A (id desc).
Usando H2 (base de datos incrustada Java), esto resulta en un escaneo completo de la tabla B. Quiero evitar un escaneo completo de la tabla.
¿Cómo puedo reescribir esta consulta para que se ejecute rápidamente? ¿Qué índice debo hacer?
Solución
select tableA.id from tableA left outer join tableB on (tableA.id = tableB.id)
where tableB.id is null
order by tableA.id desc
Si su base de datos sabe cómo hacer intersecciones de índice, esto solo tocará el índice de clave principal
Otros consejos
También puede usar Existe
, ya que a veces es más rápido que left join
. Tendría que compararlos para determinar cuál desea usar.
select
id
from
tableA a
where
not exists
(select 1 from tableB b where b.id = a.id)
Para mostrar que existe
puede ser más eficiente que un left join
, estos son los planes de ejecución de estas consultas en SQL Server 2008:
unión izquierda
- costo total del subárbol: 1.09724:
exists
- costo total del subárbol: 1.07421:
Debe verificar cada ID en la tabla A contra cada ID en la tablaB. Un RDBMS con todas las funciones (como Oracle) podría optimizar eso en un ESCANEO RÁPIDO COMPLETO DE ÍNDICE y no tocar la mesa en absoluto. No sé si el optimizador de H2 es tan inteligente como eso.
H2 admite la sintaxis MINUS, por lo que debe probar esto
select id from tableA
minus
select id from tableB
order by id desc
Eso puede funcionar más rápido; Sin duda, vale la pena compararlo.
Para mi pequeño conjunto de datos, Oracle ofrece a casi todas estas consultas el mismo plan exacto que usa los índices de clave principal sin tocar la tabla. La excepción es la versión MINUS que logra obtener menos resultados consistentes a pesar del mayor costo del plan.
--Create Sample Data.
d r o p table tableA;
d r o p table tableB;
create table tableA as (
select rownum-1 ID, chr(rownum-1+70) bb, chr(rownum-1+100) cc
from dual connect by rownum<=4
);
create table tableB as (
select rownum ID, chr(rownum+70) data1, chr(rownum+100) cc from dual
UNION ALL
select rownum+2 ID, chr(rownum+70) data1, chr(rownum+100) cc
from dual connect by rownum<=3
);
a l t e r table tableA Add Primary Key (ID);
a l t e r table tableB Add Primary Key (ID);
--View Tables.
select * from tableA;
select * from tableB;
--Find all rows in tableA that don't have a corresponding row in tableB.
--Method 1.
SELECT id FROM tableA WHERE id NOT IN (SELECT id FROM tableB) ORDER BY id DESC;
--Method 2.
SELECT tableA.id FROM tableA LEFT JOIN tableB ON (tableA.id = tableB.id)
WHERE tableB.id IS NULL ORDER BY tableA.id DESC;
--Method 3.
SELECT id FROM tableA a WHERE NOT EXISTS (SELECT 1 FROM tableB b WHERE b.id = a.id)
ORDER BY id DESC;
--Method 4.
SELECT id FROM tableA
MINUS
SELECT id FROM tableB ORDER BY id DESC;
No puedo decir cuál de estos métodos será mejor en H2 (o incluso si todos funcionarán), pero escribí un artículo que detalla todos los (buenos) métodos disponibles en TSQL. Puede darles una oportunidad y ver si alguno de ellos funciona para usted:
select parentTable.id from parentTable
left outer join childTable on (parentTable.id = childTable.parentTableID)
where childTable.id is null