UPDATE FROM с JOIN over ctid ведет к сканированию Seq - PullRequest
0 голосов
/ 27 июня 2019

Чтобы прояснить мою проблему, я создал тестовую таблицу со следующей структурой.

CREATE TABLE public.test_large (
    id int4 NOT NULL, -- Primary Key
    grp int4 NULL, -- Group ID
    descr text NULL,
    CONSTRAINT pk_test_large PRIMARY KEY (id)
);
CREATE INDEX ix_tl_grp ON public.test_large USING btree (grp);

Значения в столбце grp назначаются таким образом, чтобы в каждой записи было не более 1000 записей с одинаковыми значениями. Всего 1 000 000 записей.

Следующий оператор обновления является упрощенной версией реального оператора:

update
    test_large d
set
    descr = s.descr
from
    (
    select
        ctid,
        *
    from
        test_large
    where
        grp = 1) s
where
    s.ctid = d.ctid;

План выполнения:

Update on test_large d  (cost=139792.82..144832.96 rows=1000 width=53)
  ->  Merge Join  (cost=139792.82..144832.96 rows=1000 width=53)
        Merge Cond: (d.ctid = test_large.ctid)
        ->  Sort  (cost=136816.68..139329.25 rows=1005029 width=14)
              Sort Key: d.ctid
              ->  Seq Scan on test_large d  (cost=0.00..19443.29 rows=1005029 width=14)
        ->  Sort  (cost=2976.14..2978.64 rows=1000 width=39)
              Sort Key: test_large.ctid
              ->  Bitmap Heap Scan on test_large  (cost=20.18..2926.31 rows=1000 width=39)
                    Recheck Cond: (grp = 1)
                    ->  Bitmap Index Scan on ix_tl_grp  (cost=0.00..19.93 rows=1000 width=0)
                          Index Cond: (grp = 1)

Как видите, для обновления выполняется Seq Scan всех 1 000 000 строк, чтобы затем выполнить объединение слиянием вместо прямого доступа к строке через CTID.

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

...