Я хочу заменить все содержимое таблицы, не влияя ни на какие входящие SELECT
операторы во время процесса.
Вариант использования - иметь таблицу, в которой хранится информация о почтовом ящике, которая регулярно извлекается и должна храниться в таблице PostgreSQL. Многие клиенты используют приложение, которое постоянно запрашивает ту же таблицу.
Обычно я бы сделал что-то вроде (входящий псевдокод) ...
BEGIN TRANSACTION
TRUNCATE TABLE
INSERT INTO
COMMIT
Но, к сожалению, таблица не может быть прочитана во время этого процесса; из-за времени, необходимого INSERT INTO
для завершения. Стол заблокирован.
В MySQL я бы использовал их атомарную RENAME TABLE
команду, чтобы избежать этих проблем ...
CREATE TABLE table_new LIKE table;
INSERT INTO table_new;
RENAME TABLE table TO table_old, table_new TO table; *atomic operation*
DROP TABLE table_old;
Как я могу добиться этого в PostgreSQL?
Для целей этого вопроса вы можете предположить, что я не использую внешние ключи.
источник
TRUNCATE
команда получит блокировку AccessExclusive для таблицы, поэтому никто другой не сможет читать из таблицы, пока эта транзакция не будет зафиксирована или откатана.delete
вместоtruncate
этого будет медленнее, но без блокировки читателей. Сколько строк нужно удалить?DELETE
иINSERT
будет слишком долго.Ответы:
Правильно,
TRUNCATE TABLE
команда вы выполняете «... получает блокировку ACCESS EXCLUSIVE на каждом столе она работает на », так что в первом блоке SQL вы публикуемую любые другие клиенты , пытающиеся получить доступ к таблице после этого времени не будет заблокирован , пока вашINSERT
отделок и тыCOMMIT
.Вы можете использовать тот же обходной путь, что и в вашем специфичном для MySQL коде; Postgres поддерживает примерно такой же синтаксис и будет иметь похожее поведение блокировки. Для остроумия:
Дополнительный бонус: Postgres на самом деле поддерживает транзакционный DDL, в отличие от MySQL, поэтому в случае, если вам нужно откатить вышеупомянутую транзакцию, вы можете смело делать это.
источник
LOCK TABLE
предложенный вами метод, нужно ли мне сноваCOMMIT
его разблокировать, или он сам разблокируется?_old
-- LOCK TABLE "table" IN ROW EXCLUSIVE mode;
) кажется недостаточным для защиты от обновления / вставки в исходную таблицу в соответствии со спецификациями. ДвеROW EXCLUSIVE
блокировки могут быть получены без какого-либо конфликта (см. Таблицу 13.2 в postgresql.org/docs/10/explicit-locking.html#LOCKING-TABLES ). Для предотвращения обновления данных вам нужна как минимумSHARE
блокировка.