Pull to refresh
АО «ГНИВЦ»
Драйвер цифровой трансформации

И ещё раз о внешних ключах

Выяснилось, что мы можем повлиять на механику создания/валидации внешних ключей таким же образом, каким мы можем повлиять на план исполнения обычного SQL-запроса.

Мой тестовый пример (все имена реальных объектов заменены, планы и цифры реальные). Выполняю 3 варианта валидации FK c разными настройками сессии, план исполнения смотрю через расширение pg_query_state.

Исполнение "по умолчанию" выбирается merge join.
ALTER TABLE child_t VALIDATE CONSTRAINT fk_child_parent;

select plan from pg_query_state(1483434);
                                                          plan
------------------------------------------------------------------------------------------------------------------------
 Merge Anti Join (Current loop: actual rows=0, loop number=1)                                                          +
   Merge Cond: (fk.entity_egrn_id = pk.id)                                                                             +
   ->  Index Only Scan using child_t_idx1 on child_t fk (Current loop: actual rows=1, loop number=1)    +
         Index Cond: (entity_egrn_id IS NOT NULL)                                                                      +
         Heap Fetches: 1                                                                                               +
   ->  Index Only Scan using parent_t_pkey on parent_t pk (Current loop: actual rows=113215, loop number=1)+
         Heap Fetches: 113215
(1 row)

SET enable_mergejoin TO false;
ALTER TABLE child_t VALIDATE CONSTRAINT fk_child_parent;

 select plan from pg_query_state(1483434);
                                             plan
-----------------------------------------------------------------------------------------------
 Hash Anti Join (Current loop: actual rows=0, loop number=1)                                  +
   Hash Cond: (fk.entity_egrn_id = pk.id)                                                     +
   ->  Seq Scan on child_t fk (Current loop: actual rows=1, loop number=1)            +
         Filter: (entity_id IS NOT NULL)                                                 +
   ->  Hash (Current loop: actual rows=0, loop number=1)                                      +
         Buckets: 67108864  Batches: 8  Memory Usage: 165802kB                                +
         ->  Seq Scan on parent_t pk (Current loop: actual rows=33979819, loop number=1)

SET enable_hashjoin TO false;
SET enable_mergejoin TO false;
ALTER TABLE child_t VALIDATE CONSTRAINT fk_child_parent;

select plan from pg_query_state(1483434);
                                               plan
---------------------------------------------------------------------------------------------------
 Nested Loop Anti Join (Current loop: actual rows=0, loop number=1)                               +
   ->  Seq Scan on child_t fk (Current loop: actual rows=329042, loop number=1)           +
         Filter: (entity_id IS NOT NULL)                                                     +
   ->  Index Only Scan using parent_t_pkey on parent_t pk (actual rows=1 loops=329041)+
         Index Cond: (id = fk.entity_id)                                                     +
         Heap Fetches: 329041

Почему всё это может быть важно:
1. Вы банально могли что-то делать в своей сессии и манипулировать её состоянием, например, "форсить" вычитку через Nested Loop, а затем запустить построение/валидацию FK на громадных таблицах.
2. По каким-то причинам PG выбрал неподходящий план, и вы знаете, что другой способ будет наверняка лучше :)

Tags:
Total votes 3: ↑3 and ↓0+3
Comments0

Articles

Information

Website
www.gnivc.ru
Registered
Founded
1977
Employees
1,001–5,000 employees
Location
Россия