J'ai une relation 1: 1 entre deux tables. Je veux trouver 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. En plus des index de clé primaire, j'ai aussi un index sur tableA (id desc).
Avec H2 (base de données Java intégrée), il en résulte 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?
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 sait comment faire les intersections d'index, cela ne touchera que l'index de clé primaire
Vous pouvez également utiliser exists
, 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 exists
peut être plus efficace qu'un left join
, voici les plans d'exécution de ces requêtes dans SQL Server 2008:
left join
- coût total de la sous-arborescence: 1.09724:
exists
- coût total de la sous-arborescence: 1.07421:
Vous devez vérifier chaque ID de la tableA par rapport à chaque ID de la tableB. Un SGBDR complet (tel que Oracle) serait capable d'optimiser cela 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 supporte 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 qui utilise les index de clé primaire sans toucher à la table. L'exception est la version MINUS qui parvient à générer moins de gains cohérents malgré le coût pré-budgété plus élevé.
--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 toutes vont fonctionner), 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:
select parentTable.id from parentTable
left outer join childTable on (parentTable.id = childTable.parentTableID)
where childTable.id is null