Chcę zastąpić całą zawartość tabeli, nie wpływając na żadne przychodzące SELECT
instrukcje podczas procesu.
Przypadkiem użycia jest posiadanie tabeli, która przechowuje informacje o skrzynce pocztowej, które są regularnie wyodrębniane i muszą być przechowywane w tabeli PostgreSQL. Jest wielu klientów korzystających z aplikacji, która stale odpytuje tę samą tabelę.
Normalnie zrobiłbym coś takiego (przychodzący pseudokod) ...
BEGIN TRANSACTION
TRUNCATE TABLE
INSERT INTO
COMMIT
Niestety nie można odczytać tabeli podczas tego procesu; ze względu na czas potrzebny INSERT INTO
do ukończenia. Stół jest zamknięty.
W MySQL użyłbym ich RENAME TABLE
polecenia atomowego, aby uniknąć tych problemów ...
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;
Jak mogę to osiągnąć w PostgreSQL?
Na potrzeby tego pytania możesz założyć, że nie używam kluczy obcych.
postgresql
Clarkey
źródło
źródło
TRUNCATE
polecenie uzyska blokadę AccessExclusive na stole, więc nikt inny nie będzie mógł odczytać z tabeli, dopóki transakcja nie zostanie zatwierdzona lub wycofana.delete
zamiast tegotruncate
, będzie wolniejszy, ale bez blokowania czytników. Ile wierszy musisz usunąć?DELETE
iINSERT
byłby zdecydowanie za długi.Odpowiedzi:
Tak,
TRUNCATE TABLE
polecenie , które wykonujesz „... uzyskuje blokadę WYŁĄCZNIE DOSTĘPU dla każdej tabeli, na której działa ”, więc w pierwszym wysłanym bloku SQL wszyscy inni klienci próbujący uzyskać dostęp do tabeli po tym czasie będą blokowani do czasuINSERT
zakończenia aCOMMIT
.Możesz użyć tego samego obejścia, co w kodzie specyficznym dla MySQL; Postgres obsługuje mniej więcej tę samą składnię i będzie miał podobne zachowanie blokowania. To znaczy:
Dodatkowy bonus: Postgres faktycznie obsługuje transakcyjny DDL, w przeciwieństwie do MySQL, więc w razie potrzeby ODWRÓCENIA powyższej transakcji, możesz to zrobić bezpiecznie.
źródło
LOCK TABLE
metody, którą zasugerowałeś, czy musiałbym ją odblokować przedCOMMIT
, czy sam się odblokuje?_old
-- LOCK TABLE "table" IN ROW EXCLUSIVE mode;
) wydaje się być niewystarczający do ochrony przed aktualizacją / wstawieniem do tabeli źródłowej zgodnie ze specyfikacją. DwieROW EXCLUSIVE
blokady można uzyskać bez żadnego konfliktu (patrz Tabela 13.2 w postgresql.org/docs/10/explicit-locking.html#LOCKING-TABLES ). Aby zapobiec aktualizacjom danych, potrzebujesz przynajmniejSHARE
blokady.