Desejo substituir todo o conteúdo de uma tabela, sem afetar nenhuma SELECT
declaração recebida durante o processo.
O caso de uso é ter uma tabela que armazena informações da caixa de correio extraídas regularmente e precisa ser armazenada em uma tabela do PostgreSQL. Existem muitos clientes usando um aplicativo que está constantemente consultando a mesma tabela.
Normalmente, eu faria algo como (pseudocódigo de entrada) ...
BEGIN TRANSACTION
TRUNCATE TABLE
INSERT INTO
COMMIT
Infelizmente, porém, a tabela não pode ser lida durante esse processo; devido ao tempo necessário INSERT INTO
para concluir. A mesa está trancada.
No MySQL, eu teria usado seu RENAME TABLE
comando atômico para evitar esses problemas ...
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;
Como eu consegui isso no PostgreSQL?
Para os fins desta pergunta, você pode assumir que não estou usando chaves estrangeiras.
fonte
TRUNCATE
comando adquirirá um bloqueio AccessExclusive na tabela, para que ninguém mais possa ler a tabela até que a transação seja confirmada ou revertida.delete
veztruncate
dele, será mais lento, mas sem bloquear os leitores. Quantas linhas você precisa excluir?DELETE
eINSERT
seria muito longo.Respostas:
Certo, o
TRUNCATE TABLE
comando que você está executando "... adquire um bloqueio ACCESS EXCLUSIVE em cada tabela em que opera "; portanto, no primeiro bloco SQL que você postou, quaisquer outros clientes que tentarem acessar a tabela após esse período serão bloqueados até que vocêINSERT
termine. e vocêCOMMIT
.Você pode usar a mesma solução alternativa que no seu código específico do MySQL; O Postgres suporta aproximadamente a mesma sintaxe e terá um comportamento de bloqueio semelhante. A saber:
Bônus extra: O Postgres realmente suporta DDL transacional, ao contrário do MySQL, portanto, caso você precise ROLLBACK a transação acima, você pode fazê-lo com segurança.
fonte
LOCK TABLE
método que você sugeriu, precisaria desbloqueá-lo novamente antes doCOMMIT
, ou será desbloqueado?_old