我想替换一个表的全部内容,而不影响过程中任何传入的SELECT
语句。
用例是有一个表,用于存储定期提取的邮箱信息,并且需要存储在 PostgreSQL 表中。有许多客户端使用不断查询同一张表的应用程序。
通常,我会做类似(伪代码传入)...
BEGIN TRANSACTION
TRUNCATE TABLE
INSERT INTO
COMMIT
Run Code Online (Sandbox Code Playgroud)
但不幸的是,在此过程中无法读取该表;由于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;
Run Code Online (Sandbox Code Playgroud)
我如何在 PostgreSQL 中实现这一点?
对于这个问题,您可以假设我没有使用外键。
Jos*_*idt 25
是的,您正在执行的TRUNCATE TABLE
命令“...在其操作的每个表上获得一个 ACCESS EXCLUSIVE 锁”,因此在您发布的第一个 SQL 块中,在该时间之后尝试访问该表的任何其他客户端都将被阻止,直到您INSERT
完成而你COMMIT
。
您可以使用与 MySQL 特定代码相同的解决方法;Postgres 支持大致相同的语法,并将具有类似的锁定行为。以机智:
BEGIN;
-- You probably want to make sure that no one else is
-- INSERT / UPDATE / DELETE'ing from the original table, otherwise
-- those changes may be lost during this switchover process. One way
-- to do that would be via:
-- LOCK TABLE "table" IN SHARE ROW EXCLUSIVE mode;
CREATE TABLE "table_new" (LIKE "table");
INSERT INTO "table_new" ...;
-- The ALTER TABLE ... RENAME TO command takes an Access Exclusive lock on "table",
-- but these final few statements should be fast.
ALTER TABLE "table" RENAME TO "table_old";
ALTER TABLE "table_new" RENAME TO "table";
DROP TABLE "table_old";
COMMIT;
Run Code Online (Sandbox Code Playgroud)
额外的好处:Postgres 实际上支持事务性 DDL,不像 MySQL,所以如果你需要回滚上述事务,你可以安全地这样做。
归档时间: |
|
查看次数: |
20200 次 |
最近记录: |