【问题标题】:move data from one table to another, postgresql edition将数据从一个表移动到另一个表,postgresql 版本
【发布时间】:2014-02-11 17:41:01
【问题描述】:

我想将一些数据从一个表移动到另一个表(可能使用不同的架构)。想到的直截了当的解决方案是 -

start a transaction with serializable isolation level;
INSERT INTO dest_table SELECT data FROM orig_table,other-tables WHERE <condition>;
DELETE FROM orig_table USING other-tables WHERE <condition>;
COMMIT;

现在,如果数据量很大,而 &lt;condition&gt; 的计算成本很高怎么办?在 PostgreSQL 中,规则或存储过程可用于动态删除数据,只评估一次条件。哪种解决方案更好?还有其他选择吗?

【问题讨论】:

    标签: sql postgresql


    【解决方案1】:

    [扩展至dvv's answer]

    您可以按如下方式移动到现有表。对于不匹配的架构,您应该指定列。

    WITH moved_rows AS (
        DELETE FROM <original_table> a
        USING <other_table> b
        WHERE <condition>
        RETURNING a.* -- or specify columns
    )
    INSERT INTO <existing_table> --specify columns if necessary
    SELECT [DISTINCT] * FROM moved_rows;
    

    但是你想将数据移动到一个新的表中(不是现有的),外部语法不同: p>

    CREATE TABLE <new_table> AS
    WITH moved_rows AS (
        DELETE FROM <original_table> a
        USING <other_table> b
        WHERE <condition>
        RETURNING a.* -- or specify columns
    )
    SELECT [DISTINCT] * FROM moved_rows;
    

    【讨论】:

    • 我使用 pg10.1 和 CREATE TABLE xxx AS DELETE FROM yyy 导致语法错误。这里的后一个示例是一个很好的解决方法。
    • 这个操作是原子的吗? DELETEINSERT 之间会发生什么吗?
    • @AndreySemakin 粗略的搜索表明单个语句不一定是原子的——至少不是你认为的那样。 HereHereHereHere。如果您的应用程序需要原子性,您可能希望将其包装在 TRANSACTION 中。我建议您对 ACID 特性进行更多的研究和研究。 (我不再积极处理数据库,所以我不能再进一步了。)
    【解决方案2】:

    您可以在 Postgres 9.1 中使用 SINGLE 查询移动数据 见http://www.postgresql.org/docs/9.1/static/queries-with.html “WITH 中的数据修改语句”部分

    【讨论】:

    • 我查了一下,比插入选择+删除要慢
    【解决方案3】:

    如果条件非常复杂以至于您不想执行两次(顺便说一句,这对我来说不太可能,但无论如何),一种可能性是在原始表上 ALTER TABLE ... ADD COLUMN 添加一个布尔字段,然后在表上运行UPDATE 以将该字段设置为真WHERE &lt;condition&gt;。然后您的 INSERTDELETE 命令可以简单地检查此列中的 WHERE 子句。

    之后不要忘记从源表和目标表中删除该列!

    嗯,创建一个新的临时表,其唯一目的是包含您想要包含的记录的 PK,这样的侵入性就更小了。首先INSERT 到该表“定义”要操作的行集,然后与该表连接以复制表INSERTDELETE。由于表 PK 已编入索引,因此这些连接会很快。


    [编辑] Scott Bailey 在 cmets 中的建议显然是正确的做法,希望我自己能想到!假设所有原始表的 PK 字段都将出现在目标表中,不需要临时表 -- 只需使用复杂的WHERE 条件插入目标,然后将DELETE 从通过加入该表来创建原始表。我觉得现在建议单独的桌子很愚蠢! :)

    【讨论】:

    • 临时表得到我的投票。更新行然后删除它们意味着在堆中创建大量垃圾,并且需要接触表模式(这并不重要)
    • 您不需要临时表或进行两次昂贵的计算。插入新表时执行一次计算。然后从新表中记录的旧表中删除。
    • 目标表也会有大量数据,所以这个 DELETE 语句可能很大。你的想法不错,但我仍在寻找更快的方法。
    • @IggShaman:虽然我不排除它,但我看不出有什么能更快,除非编写一个 C 扩展,以某种方式将现有行重新连接到新表中磁盘级别(无论如何这可能是不可能的)。顺便说一句,如果您的目标表上有一个包含源表的所有 PK 字段的索引,PostgreSQL 将只读取索引而不是整个表。
    【解决方案4】:

    您可以将表数据转储到文件中,然后使用COPY 将其插入到另一个表中 通常COPYINSERT 快​​。

    【讨论】:

    • 我进行了一些测试,使用触发器逐行处理大量数据,并使用带有单个事务的存储过程。存储过程方法更快。
    • 您还应该微调您的 PostgreSQL 服务器以提高性能。阅读:wiki.postgresql.org/wiki/Performance_Optimization
    • 是的,我认为该准则应该有资格说一个 COPY 比一组 INSERT 语句快,每行一个。 INSERT...SELECT 用于复制数据我认为是最佳的,因为数据没有在执行程序之外传递。
    • 复制比插入外部数据要快。 OP 正在处理数据库中已有的数据,因此插入比导出然后复制回来要快。
    猜你喜欢
    • 2012-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多