【问题标题】:Replace rows from another table替换另一个表中的行
【发布时间】:2016-02-03 22:05:32
【问题描述】:

我有两个具有完全相同列的表。第一个用于生产,Web 应用程序(django)从中检索对象以显示在网页上。 我正在使用 Python 脚本将对象添加到第二个。 脚本完成后,我需要将 table-1 中的所有行替换为 table-2 中的行。现在我正在使用这样的东西:

TRUNCATE table-1;
INSERT INTO table-1 (columns) SELECT columns FROM table-2;
TRUNCATE table-2;
VACUUM FULL;

问题是它花费了太长时间,并且在 TRUNCATE table-1 之后网站在 INSERT 完成之前毫无用处。解决这个问题的最佳方法是什么?

【问题讨论】:

  • 对 table_1 使用 delete 而不是 truncate。这将允许在您提交之前对table_1 进行读取访问。
  • 添加where语句,假设插入太长,因为表很大

标签: sql postgresql


【解决方案1】:

您可以尝试创建一个视图并针对它编写 django 代码。当需要在 table1 和 table2 之间切换时,只需 create or replace view 切换到另一个表。

【讨论】:

    【解决方案2】:

    您根本不需要昂贵的VACUUM FULL。就在你的大 INSERT 之后,没有什么需要清理的了。没有死元组,所有索引都处于原始状态。

    运行ANALYZE 可以立即更新完全更改的表统计信息。

    对于小型表DELETE 可能比TRUNCATE 快,但对于中型到大型表TRUNCATE 通常更快。

    在一个事务中完成所有操作。 INSERT 在同一事务中 TRUNCATE 之后不必写入 WAL 并且速度更快:

    BEGIN;
    TRUNCATE table1;
    INSERT INTO table1 TABLE table2;
    TRUNCATE table2;  -- do you need this?
    ANALYZE table1;  -- might be useful 
    COMMIT;
    

    详情:

    如果您在 table1 上有任何索引,则需要先删除它们,然后在 INSERT 之后重新创建它们以用于大表。

    如果您没有依赖对象,您也可以删除 table1 并重命名 table2,这样会快得多

    任何一种方法都需要在表上使用排他锁。但是你一直在用VACUUM FULL previously which takes an exclusive lock as well:

    VACUUM FULL 将表的全部内容重写到新磁盘中 没有额外空间的文件,允许将未使用的空间返回到 操作系统。这种形式要慢得多,需要独占 在处理每个表时锁定它。

    因此可以安全地假设您可以使用独占锁。

    【讨论】:

    • 但是truncate会在表上获取访问排他锁,这样在事务过程中,表甚至不能被读取(我的理解是,这就是问题所在)跨度>
    • @a_horse_with_no_name:我认为在完全重写表的同时允许并发读取没有任何意义。所以这是一个功能,而不是错误。
    • 我从未说过这是一个错误。但是在替换数据的整个过程完成之前,我确实认为允许客户端查看表的先前(一致)状态是有意义的。毕竟这就是交易的目的。
    • @a_horse_with_no_name:为多种目的“进行”交易。一旦我决定替换表的内容,我可能希望任何更多的并发事务来读取旧内容。
    • 取决于要求。我们实际上确实有一些表(存储例如聚合数据),我们正是实现了这一点。我们甚至在单个事务中使用多个表来执行此操作(例如,在将内容从登台发布到实时环境时用于内容管理系统)。我并不觉得这个要求特别令人惊讶;)
    猜你喜欢
    • 1970-01-01
    • 2021-01-01
    • 2022-11-17
    • 2023-01-25
    • 2021-08-19
    • 1970-01-01
    • 2016-01-01
    • 2020-03-20
    • 1970-01-01
    相关资源
    最近更新 更多