Как оптимизировать удаление строк из большой таблицы, имеющей ссылочную целостность? - PullRequest
1 голос
/ 18 июня 2020

Если у меня маленькая таблица с внешним ключом (FK) к большой таблице. Когда я удаляю элементы из большой таблицы, postgres тратит много времени на вызов триггера для ограничения FK.

Пример:

DROP TABLE IF EXISTS large_table CASCADE;
DROP TABLE IF EXISTS small_table CASCADE;

CREATE TABLE large_table (
    id serial primary key,
    name text
);

CREATE TABLE small_table (
    id serial primary key,
    large_table_id serial REFERENCES large_table(id) ON DELETE CASCADE
);

INSERT INTO
    large_table (name)
SELECT
    md5(random() :: text)
FROM
    generate_series(1, 500000) s(i);

-- (in reality we'll be deleting a subset of rows)
EXPLAIN ANALYZE DELETE FROM "large_table"; 

Delete on large_table  (cost=0.00..9459.09 rows=529209 width=6) (actual time=516.400..516.400 rows=0 loops=1)
  ->  Seq Scan on large_table  (cost=0.00..9459.09 rows=529209 width=6) (actual time=0.013..57.192 rows=500000 loops=1)
Planning Time: 0.055 ms
Trigger for constraint small_table_large_table_id_fkey: time=2272.971 calls=500000
Execution Time: 2810.341 ms

Хотя нет данных в small_table, postgres тратит ~ 2 секунды Trigger for constraint small_table_large_table_id_fkey. Есть ли способ оптимизировать это, не отключая все триггеры в таблице?

Postgresql 12,1

1 Ответ

1 голос
/ 18 июня 2020

Это время 0,005 миллисекунды на проверку, что, на мой взгляд, не так уж и плохо.

Вы не можете пропустить проверку, если хотите сохранить ссылочную целостность.

Как суперпользователь , вы могли бы сделать

BEGIN;
SET LOCAL session_replication_role = replica;
DELETE FROM large_table;
COMMIT;

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...