【发布时间】:2014-12-01 11:55:59
【问题描述】:
我目前正在分析比特币区块链。我的 postgresql 数据库中有以下表格:
- 发送:11GB
- txin:40GB
- 输出:37GB
为了加快我的分析查询,我从表中复制列。 tx.id、txout.tx_id 和 txout.txout_id 上有索引。要将列 txout_id 从表 txout 复制到表 tx,我执行了以下查询:
第一个查询:
UPDATE tx
SET txout_id = txout.txout_id
FROM tx as t1
INNER JOIN txout
ON t1.id = txout.tx_id
第二个查询: SELECT tx.*, txout.txout_id
INTO tx_txoutID
FROM tx
INNER JOIN txout
ON tx.id = txout.tx_id
我在 75 分钟后取消了第一个查询。第二个查询在 20 分钟后完成。第二个查询要求我删除 tx,重命名 tx_txoutID,然后为 tx 创建索引。现在我想知道是否有一个查询,它和第二个查询一样快,和第一个查询一样舒服。
编辑:txout_id 最初不是 tx 的一部分,但已通过更改表添加到第一条语句。
【问题讨论】:
-
为什么要使用两次 tx? UPDATE tx SET txout_id = txout.txout_id FROM txout WHERE t1.id = txout.tx_id;
-
这是一个常见的误解,正如@FrankHeikens 指出的那样:如果你在
WHERE子句中提到当前更新的表,你创建了一个(大部分是无意的)自连接:postgresql.org/docs/current/static/sql-update.html#AEN81996(参见参数from_list) -
您能告诉我们 EXPLAIN ANALYZE 的结果吗? work_mem 的设置是什么?调整 work_mem 有助于这次大型更新,对于 checkpoint_segments 等检查点参数也是如此。
-
正常情况下,UPDATE 比创建具有全新内容的新表要慢得多。 UPDATE 单独锁定并重新定位每一行,并且还必须更新每个索引条目。在你有 3 个索引的情况下,我敢打赌它会慢 5-10 倍。
-
索引指向该行,该行由于 MVCC 被重新定位(=需要保留旧值)。请参阅stackoverflow.com/questions/3361291 或dba.stackexchange.com/questions/52517 了解更多信息,但基本上您会发现您的方法#2 是最佳的。
标签: sql postgresql join