Как найти строки в одной таблице, у которых нет соответствующей строки в другой таблице - PullRequest
62 голосов
/ 12 сентября 2009

У меня есть соотношение 1: 1 между двумя таблицами. Я хочу найти все строки в таблице A, которые не имеют соответствующей строки в таблице B. Я использую этот запрос:

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

id - это первичный ключ в обеих таблицах. Помимо индексов первичного ключа у меня также есть индекс для tableA (id desc).

Использование H2 (встроенная база данных Java) приводит к полному сканированию таблицы tableB. Я хочу избежать полного сканирования таблицы.

Как мне переписать этот запрос для быстрого выполнения? Какой индекс мне следует?

Ответы [ 6 ]

87 голосов
/ 12 сентября 2009
select tableA.id from tableA left outer join tableB on (tableA.id = tableB.id)
where tableB.id is null
order by tableA.id desc 

Если ваша БД знает, как выполнять пересечения индексов, это коснется только индекса первичного ключа

30 голосов
/ 12 сентября 2009

Вы также можете использовать exists, так как иногда это быстрее, чем left join. Вам нужно сравнить их, чтобы понять, какой из них вы хотите использовать.

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

Чтобы показать, что exists может быть более эффективным, чем left join, вот планы выполнения этих запросов в SQL Server 2008:

left join - общая стоимость поддерева: 1.09724:

left join

exists - общая стоимость поддерева: 1.07421:

exists

6 голосов
/ 12 сентября 2009

Вы должны проверить каждый идентификатор в таблице A против каждого идентификатора в таблице B. Полнофункциональная СУБД (например, Oracle) сможет оптимизировать ее в INDEX FULL FAST SCAN и вообще не касаться таблицы. Я не знаю, настолько ли у него оптимизатор H2.

H2 поддерживает синтаксис MINUS, поэтому вы должны попробовать это

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

Это может работать быстрее; это, безусловно, стоит сравнить.

5 голосов
/ 10 декабря 2010

Для моего небольшого набора данных Oracle предоставляет почти все эти запросы точно в том же плане, который использует индексы первичного ключа, не касаясь таблицы. Исключением является версия MINUS, которой удается делать меньше последовательных запросов, несмотря на более высокую стоимость плана.

--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;
3 голосов
/ 12 сентября 2009

Я не могу сказать вам, какой из этих методов будет лучшим в H2 (или даже если все они будут работать), но я написал статью, подробно описывающую все (хорошие) методы, доступные в TSQL. Вы можете дать им шанс и посмотреть, подходит ли вам какой-либо из них:

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

0 голосов
/ 21 июля 2018
select parentTable.id from parentTable
left outer join childTable on (parentTable.id = childTable.parentTableID) 
where childTable.id is null
...