Cómo encontrar filas en una tabla que no tengan una fila correspondiente en otra tabla

StackOverflow https://stackoverflow.com/questions/1415438

  •  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?

¿Fue útil?

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:

combinación izquierda

exists - costo total del subárbol: 1.07421:

existe

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:

http://code.msdn.microsoft .com / SQLExamples / Wiki / View.aspx? title = QueryBasedUponAbsenceOfData & amp; refereTitle = Inicio

select parentTable.id from parentTable
left outer join childTable on (parentTable.id = childTable.parentTableID) 
where childTable.id is null
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top