те записи которых нету в другой таблицы на 1 млн записей. С помощью запроса SELECT id FROM table WHERE id not in (SELECT id FROM temp) . Запрос что-то долго выполняется. Будет ли быстрей если заменить not exists ?
https://t.me/pgsql/303899
Скорее всего быстрее будет LEFT OUTER JOIN, где поле в правой таблице NULL
Подскажите, кто знает, в подобных запросах подчиненный SELECT выполнится один раз, и его результаты будут использованы многократно, или для каждой записи (SELECT id FROM temp) будет выполняться повторно?
А в плане запроса этого не видно?
Придется ставить эксперимент
Там зависит от числа записей. Для небольшого числа - nested loop + index_scan, если очень много - merge_join, где-то посерединке (или если в одной таблице отбираемых записей гораздо меньше, чем в другой) - hash_join
Вангую что разницы не будет никакой. Думаю это как раз случай иллюстрирующий то что синтаксис языка SQL позволяет абстрагироваться от способа доступа, который оптимизатор выбирает на свое усмотрение. И ни что не мешает ему построить два идентичных плана на разные тексты запросов.
Поменял на запрос LEFT JOIN table1 ON (table2.id=table1.id) WHERE table1.id IS NULL . Отработал за 5 секунд . прошлый запрос спустя пол часа так и не завершился
Похоже это какие-то заморочки оптимизатора постгреса. Тест create table t1 (a integer); create table t2 (a integer); insert into t1 values(1); insert into t1 values(2); insert into t1 values(3); insert into t1 values(4); insert into t1 values(5); insert into t1 values(6); insert into t1 values(7); insert into t2 values(1); insert into t2 values(2); insert into t2 values(3); insert into t2 values(4); insert into t2 values(5); analyze t1; analyze t2; explain select a from t1 where a not in (select a from t2); explain select * from t1 LEFT JOIN t2 ON (t1.a=t2.a) WHERE t2.a IS NULL; показывает что в случае с WHERE id not in (SELECT id FROM temp) он делает два вложенных seqscan и фильтр между ними: "Seq Scan on t1 (cost=1.06..2.15 rows=4 width=4)" " Filter: (NOT (hashed SubPlan 1))" " SubPlan 1" " -> Seq Scan on t2 (cost=0.00..1.05 rows=5 width=4)" а в случае LEFT JOIN - хэш антиджойн "Hash Anti Join (cost=1.11..2.23 rows=2 width=8)" " Hash Cond: (t1.a = t2.a)" " -> Seq Scan on t1 (cost=0.00..1.07 rows=7 width=4)" " -> Hash (cost=1.05..1.05 rows=5 width=4)" " -> Seq Scan on t2 (cost=0.00..1.05 rows=5 width=4)" К примеру Оракл в обоих случаях сразу делает хэш-джойн --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 4 (100)| | |* 1 | HASH JOIN ANTI NA | | 164 | 4264 | 4 (0)| 00:00:01 | | 2 | TABLE ACCESS FULL| T1 | 164 | 2132 | 2 (0)| 00:00:01 | | 3 | TABLE ACCESS FULL| T2 | 164 | 2132 | 2 (0)| 00:00:01 | --------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - access("A"="A") ---------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 164 | 4264 | 4 (0)| 00:00:01 | |* 1 | FILTER | | | | | | |* 2 | HASH JOIN OUTER | | 164 | 4264 | 4 (0)| 00:00:01 | | 3 | TABLE ACCESS FULL| T1 | 164 | 2132 | 2 (0)| 00:00:01 | | 4 | TABLE ACCESS FULL| T2 | 164 | 2132 | 2 (0)| 00:00:01 | ---------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("T2"."A" IS NULL) 2 - access("T1"."A"="T2"."A"(+))
Надо заметить, что filter hash он считает быстрее hash antijoin. В принцыпе логично: join требует ещё и размножать значения таблицы и помещать туда второе отношэние. Хотя тут, понятно, должэн бы догадаться, что ничего такого быть не можэт при left join null -- но не догадался. Впрочем, боюсь, этот пример не показателен -- маленькие таблицы без ключей и индэксов.
А пры чом тут ключи и индэксы? Таплицы джойнятся цэликом, бэз филтра. В вапросе вышэ 1.5млн записей в адной таплице и 1млн ва фтарой, какие туд индэксы.
> Таплицы джойнятся цэликом, бэз филтра. Это, в общем, некоторая математическая модэль одного этапа операцыи. Которая не очень прямо преобразуется в план запроса (точнее, вообще не имеет отношэния к реальности выполнения). >В вапросе вышэ 1.5млн записей Что было в запросе вышэ -- мы можэм только гадать, потому мне нет смысла обсуждать это серьёзно.
Обсуждают сегодня