【问题标题】:SQL: UPDATE FROM JOIN much slower than SELECT INTO FROM JOINSQL:UPDATE FROM JOIN 比 SELECT INTO FROM JOIN 慢得多
【发布时间】: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/3361291dba.stackexchange.com/questions/52517 了解更多信息,但基本上您会发现您的方法#2 是最佳的。

标签: sql postgresql join


【解决方案1】:

试试这个查询:

UPDATE tx
SET txout_id = txout.txout_id
FROM txout
WHERE tx.id = txout.tx_id

您不需要将原始表添加到FROM 子句。除非您打算进行额外的自我加入。

【讨论】:

  • 这是一个帮助我优化查询的答案。但是,它并没有解决 UPDATE 查询比 SELECT INTO 查询慢得多的问题。
猜你喜欢
  • 2019-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-16
  • 1970-01-01
相关资源
最近更新 更多