如何在 Postgresql 中有效地将数百万行从一个表复制到另一个表?

Mil*_*vic 43 postgresql

我有两个数据库表。其中一个包含数亿条记录。让我们称之为那个history。另一个是每天计算的,我想将其所有记录复制到history一个中。

我所做的是运行:

INSERT INTO history SELECT * FROM daily

它在一段时间内起到了作用,但随着记录数量的不断增加,它开始变得越来越慢。现在我有大约 200 万条记录需要在单个操作中从复制daily到复制,history并且需要很长时间才能完成。

是否有另一种更有效的方法将数据从一个表复制到另一个表?

Fab*_*oni 17

以csv格式转储表格

COPY table TO '/tmp/table.csv' DELIMITER ',';
Run Code Online (Sandbox Code Playgroud)

使用 COPY 命令,它对于大量数据更有效。

COPY table FROM '/tmp/table.csv' DELIMITER ',';
Run Code Online (Sandbox Code Playgroud)

查看http://www.postgresql.org/docs/current/static/sql-copy.html 上的postgres 文档了解更多信息

  • 如果您正在填满一个空表,或者添加比现有更多的行,删除非聚集索引并在传输完成后重新创建它们通常更有效(除非当时正在使用表) ) (3认同)

Mil*_*vic 15

问题出在索引上。该history表有 160M 索引行。通过运行COPY FROM或者INSERT INTO .. SELECT它花费了大量时间而不是插入行,而是更新索引。当我禁用索引时,它在 10 秒内导入了 3M 行。现在我需要找到重新索引大表的更快方法。

  • 你甚至需要在历史表上建立索引吗? (3认同)
  • 使用 CONCURRENTLY 关键字添加索引 (2认同)

fra*_*ncs 13

您可以使用psql工具,我可能会很有效率,如下所示,

psql -h ${DAILY_HOST_IP} -p ${PG_PORT} ${DB_NAME} ${USER_NAME} -c "copy daily to stdout " | psql -h ${HISTORY_HOST_IP} -p ${PG_PORT} ${DB_NAME} ${USER_NAME}  -c "copy history from stdin"
Run Code Online (Sandbox Code Playgroud)

你也可以写一个shell脚本。


小智 10

如果您打算长时间(数月)保留历史记录,我建议查看分区选项 - 可能是每天或每周一个分区,依此类推。它也取决于您的历史表的访问模式(您是否运行跨日期访问数据的查询?您是否进行了大量聚合等)。查看用于存储聚合/摘要的物化视图。 http://www.postgresql.org/docs/9.3/static/ddl-partitioning.html http://www.postgresql.org/docs/9.3/static/sql-creatematerializedview.html