Postgres ANTI-JOIN нужен Table-Scan? - PullRequest
4 голосов
/ 11 марта 2011

Мне нужно ANTI-JOIN (не существует, SELECT что-то из таблицы ... / левая таблица соединений WHERE table.id IS NULL) в той же таблице.На самом деле у меня есть индекс для обслуживания несуществующего вопроса, но планировщик запросов выбирает использовать сканирование кучи растрового изображения.

В таблице 100 миллионов строк, поэтому сканирование кучи испортилось ...

Было бы очень быстро, если бы Postgres мог сравнить с указаниями.Должен ли Postgres посещать стол для этого ANTI-JOIN?

Я знаю, что в какой-то момент нужно посетить стол, чтобы обслуживать MVCC, но почему так рано?НЕ СУЩЕСТВУЕТ, ЧТОБЫ ТОЛЬКО УСТАНОВИТЬСЯ СТОЛОМ, потому что иначе может пропустить что-то?

Ответы [ 2 ]

7 голосов
/ 12 марта 2011

Вам потребуется предоставить сведения о версии, и, как говорит jmz, EXPLAIN ANALYZE выводит какие-либо полезные советы.

Франц - не думайте, возможно ли это, протестируйте и узнайте.

Это v9.0:

CREATE TABLE tl (i int, t text);
CREATE TABLE tr (i int, t text);
INSERT INTO tl SELECT s, 'text ' || s FROM generate_series(1,999999) s;
INSERT INTO tr SELECT s, 'text ' || s FROM generate_series(1,999999) s WHERE s % 3 = 0;
ALTER TABLE tl add primary key (i);
CREATE INDEX tr_i_idx ON tr (i);
ANALYSE;
EXPLAIN ANALYSE SELECT i,t FROM tl LEFT JOIN tr USING (i) WHERE tr.i IS NULL;
                                                         QUERY PLAN                                                      
-----------------------------------------------------------------------------------------------------------------------------
 Merge Anti Join  (cost=0.95..45611.86 rows=666666 width=15) (actual time=0.040..4011.970 rows=666666 loops=1)
   Merge Cond: (tl.i = tr.i)
   ->  Index Scan using tl_pkey on tl  (cost=0.00..29201.32 rows=999999 width=15) (actual time=0.017..1356.996 rows=999999 lo
   ->  Index Scan using tr_i_idx on tr  (cost=0.00..9745.27 rows=333333 width=4) (actual time=0.015..439.087 rows=333333 loop
 Total runtime: 4602.224 ms

То, что вы увидите, будет зависеть от вашей версии и статистики, которую видит планировщик.

0 голосов
/ 10 октября 2017

Мой (упрощенный) запрос:

SELECT a.id FROM a LEFT JOIN b ON b.id = a.id WHERE b.id IS NULL ORDER BY id;

План запроса работает следующим образом:

                                                       QUERY PLAN                                                        
-------------------------------------------------------------------------------------------------------------------------
 Merge Anti Join  (cost=0.57..3831.88 rows=128092 width=8)
   Merge Cond: (a.id = b.id)
   ->  Index Only Scan using a_pkey on a  (cost=0.42..3399.70 rows=130352 width=8)
   ->  Index Only Scan using b_pkey on b  (cost=0.15..78.06 rows=2260 width=8)
(4 rows)

Однако иногда postgresql 9.5.9 переключался на последовательное сканирование, если планировщик думал, что это может быть лучше (см. Почему PostgreSQL выполняет последовательное сканирование на индексированном столбце? ). Однако в моем случае все стало еще хуже.

                                                       QUERY PLAN                                                        
-------------------------------------------------------------------------------------------------------------------------
 Merge Anti Join  (cost=405448.22..39405858.08 rows=1365191502 width=8)
   Merge Cond: (a.id = b.id)
   ->  Index Only Scan using a_pkey on a  (cost=0.58..35528317.86 rows=1368180352 width=8)
   ->  Materialize  (cost=405447.64..420391.89 rows=2988850 width=8)
         ->  Sort  (cost=405447.64..412919.76 rows=2988850 width=8)
               Sort Key: b.id
               ->  Seq Scan on b  (cost=0.00..43113.50 rows=2988850 width=8)
(7 rows)

Мое (взломанное) решение состояло в том, чтобы препятствовать последовательному сканированию:

set enable_seqscan to off;

В документации postgresql сказано, что правильный способ сделать это - использовать seq_page_cost с помощью ALTER TABLESPACE. Это может быть целесообразно при использовании ORDER BY в индексированных столбцах, но я не уверен. https://www.postgresql.org/docs/9.1/static/runtime-config-query.html

...