Comment trouver des lignes dans une table qui n'ont pas de ligne correspondante dans une autre table

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

  •  06-07-2019
  •  | 
  •  

Question

J'ai une relation 1: 1 entre deux tables. Je souhaite rechercher toutes les lignes de la table A qui n'ont pas de ligne correspondante dans la table B. J'utilise cette requête:

SELECT id 
  FROM tableA 
 WHERE id NOT IN (SELECT id 
                    FROM tableB) 
ORDER BY id desc

id est la clé primaire dans les deux tables. Outre les index de clé primaire, j'ai aussi un index sur tableA (id desc).

Si vous utilisez H2 (base de données intégrée Java), vous obtenez une analyse complète de la tableB. Je veux éviter une analyse complète de la table.

Comment puis-je réécrire cette requête pour qu'elle s'exécute rapidement? Quel index devrais-je avoir?

Était-ce utile?

La solution

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 votre base de données sait comment effectuer les intersections d'index, cela ne touchera que l'index de clé primaire

Autres conseils

Vous pouvez également utiliser existe , car il est parfois plus rapide que left join . Vous devrez les comparer pour déterminer lequel vous voulez utiliser.

select
    id
from
    tableA a
where
    not exists
    (select 1 from tableB b where b.id = a.id)

Pour montrer que existe peut être plus efficace qu'une jointure à gauche , voici les plans d'exécution de ces requêtes dans SQL Server 2008:

jointure à gauche - coût total de la sous-arborescence: 1.09724:

rejoindre la gauche

existe - coût total de la sous-arborescence: 1.07421:

existe

Vous devez vérifier chaque ID de la tableA par rapport à chaque ID de la tableB. Un SGBDR complet (tel que Oracle) serait capable de l’optimiser dans un INDEX FULL FAST SCAN et de ne pas toucher la table du tout. Je ne sais pas si l'optimiseur de H2 est aussi intelligent que cela.

H2 prend en charge la syntaxe MINUS, vous devriez donc essayer ceci

select id from tableA
minus
select id from tableB
order by id desc

Cela peut être plus rapide. il vaut certainement la peine de procéder à une analyse comparative.

Pour mon petit ensemble de données, Oracle donne à la quasi-totalité de ces requêtes le même plan que celui qui utilise les index de clé primaire sans toucher à la table. La seule exception est la version MINUS, qui parvient à obtenir moins d’objectifs cohérents malgré le coût plus élevé du forfait.

--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;

Je ne peux pas vous dire laquelle de ces méthodes sera la meilleure sur H2 (ni même si chacune d’elles fonctionnera), mais j’ai écrit un article détaillant toutes les (bonnes) méthodes disponibles dans TSQL. Vous pouvez leur donner un coup de feu et voir si l'un d'eux fonctionne pour vous:

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

select parentTable.id from parentTable
left outer join childTable on (parentTable.id = childTable.parentTableID) 
where childTable.id is null
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top