Postgresql 大表上的Postgres更新非常慢

Postgresql 大表上的Postgres更新非常慢,postgresql,sql-update,Postgresql,Sql Update,我有一个Postgres 9.1.3表格,其中Y=1后有206万行,如下所示,它总共只有一万多行,没有任何WHERE。我正在尝试使用如下查询将数据添加到空字段: WITH B AS ( SELECT Z, rank() OVER (ORDER BY L, N, M, P) AS X FROM A WHERE Y=1 ) UPDATE A SET A.X = B.X FROM B WHERE A.Y=1 AND B.Z = A.Z; UP

我有一个Postgres 9.1.3表格,其中Y=1后有206万行,如下所示,它总共只有一万多行,没有任何WHERE。我正在尝试使用如下查询将数据添加到空字段:

WITH B AS (
    SELECT Z,
           rank() OVER (ORDER BY L, N, M, P) AS X
    FROM   A
    WHERE  Y=1
)

UPDATE A
SET A.X = B.X
FROM B
WHERE A.Y=1
  AND B.Z = A.Z;
UPDATE A
SET A.X = B.X
FROM B
WHERE A.Y=1
      AND B.Z = A.Z
      AND A.X IS DISTINCT FROM B.X;
此查询运行数小时,似乎进展非常缓慢。事实上,在我第二次尝试这个方法时,在查询运行了3个小时后,我停电了。恢复电源后,我分析了表格,得出以下结论:

INFO:  analyzing "consistent.master"
INFO:  "master": scanned 30000 of 69354 pages, containing 903542 live rows and 153552 dead rows; 30000 rows in sample, 2294502 estimated total rows
Total query runtime: 60089 ms.
在这几个小时里,查询几乎没有进展,这是正确的解释吗

在运行这个长查询之前,我已经做了一个完整的分析

WITH中的查询只需40秒

除A.X和扩展名B.X外,上面引用的所有字段都编制了索引:L、M、N、p、Y、Z

这是运行在笔记本电脑上的8GB内存,核心i7Q7201.6GHz四核处理器和Windows7x64。为了与PostGIS 1.5.3兼容,我正在运行Postgres 32位。Windows 64位PostGIS尚不可用。32位Postgres意味着它不能在Windows中使用超过2GB的RAM,但我怀疑这是一个问题

下面是解释的结果:

Update on A  (cost=727684.76..945437.01 rows=2032987 width=330)
  CTE B
    ->  WindowAgg  (cost=491007.50..542482.47 rows=2058999 width=43)
          ->  Sort  (cost=491007.50..496155.00 rows=2058999 width=43)
                Sort Key: A.L, A.N, A.M, A.P
                ->  Seq Scan on A  (cost=0.00..85066.80 rows=2058999 width=43)
                      Filter: (Y = 1)
  ->  Hash Join  (cost=185202.29..402954.54 rows=2032987 width=330)
        Hash Cond: ((B.Z)::text = (A.Z)::text)
        ->  CTE Scan on B  (cost=0.00..41179.98 rows=2058999 width=88)
        ->  Hash  (cost=85066.80..85066.80 rows=2058999 width=266)
              ->  Seq Scan on A  (cost=0.00..85066.80 rows=2058999 width=266)
                    Filter: (Y = 1)

可能有多种解决方案

更新可能被锁定。查阅pg_锁视图。 也许在一台机器上有触发器?它们可能是经济放缓的原因。 尝试解释更新…-该计划与普通选择计划是否存在显著差异?也许你可以分两步完成——将B导出到一个表,然后从该表更新。 尝试在更新之前删除索引。 创建一个新表,删除旧表,将新表重命名为旧表的名称。
可能有多种解决方案

更新可能被锁定。查阅pg_锁视图。 也许在一台机器上有触发器?它们可能是经济放缓的原因。 尝试解释更新…-该计划与普通选择计划是否存在显著差异?也许你可以分两步完成——将B导出到一个表,然后从该表更新。 尝试在更新之前删除索引。 创建一个新表,删除旧表,将新表重命名为旧表的名称。
尝试按如下方式重写查询:

WITH B AS (
    SELECT Z,
           rank() OVER (ORDER BY L, N, M, P) AS X
    FROM   A
    WHERE  Y=1
)

UPDATE A
SET A.X = B.X
FROM B
WHERE A.Y=1
  AND B.Z = A.Z;
UPDATE A
SET A.X = B.X
FROM B
WHERE A.Y=1
      AND B.Z = A.Z
      AND A.X IS DISTINCT FROM B.X;

尝试按如下方式重写查询:

WITH B AS (
    SELECT Z,
           rank() OVER (ORDER BY L, N, M, P) AS X
    FROM   A
    WHERE  Y=1
)

UPDATE A
SET A.X = B.X
FROM B
WHERE A.Y=1
  AND B.Z = A.Z;
UPDATE A
SET A.X = B.X
FROM B
WHERE A.Y=1
      AND B.Z = A.Z
      AND A.X IS DISTINCT FROM B.X;
现在,我已经多次使用它来修复一个永无止境的更新。上述模式在几分钟内完成了数百万行

有一次我遇到了主键冲突。这是通过在运行上述语句之前删除主键并在之后重新创建它来解决的。我很惊讶这是必要的,因为在我的CTE中,冲突的值在插入之前就被删除了,但是哦,好吧

现在,我已经多次使用它来修复一个永无止境的更新。上述模式在几分钟内完成了数百万行


有一次我遇到了主键冲突。这是通过在运行上述语句之前删除主键并在之后重新创建它来解决的。我很惊讶这是必要的,因为在我的CTE中,冲突的值在插入之前被删除,但是哦,好吧。

我不理解这些数字。该表包含200万行。Y=1的条件从中选择了多少行?请发布解释或完成解释分析输出。如果Y=1部分具有很强的选择性,如在随机生成的数据中,则更新将在毫秒内完成。所以,请提供一个数据示例。刚刚做了第三次尝试,让它运行了一整夜。到目前为止,它已经运行了17.6个小时,尚未完成。你们都有好问题。今天晚些时候我必须提供答案。只是添加了解释结果。我会在今晚,大概7个多小时后,再回到这个话题上,以获取所需的其他信息。我不明白这些数字。该表包含200万行。Y=1的条件从中选择了多少行?请发布解释或完成解释分析输出。如果Y=1部分具有很强的选择性,如在随机生成的数据中,则更新将在毫秒内完成。所以,请提供一个数据示例。刚刚做了第三次尝试,让它运行了一整夜。到目前为止,它已经运行了17.6个小时,尚未完成。你们都有好问题。今天晚些时候我必须提供答案。只是添加了解释结果。我会在今晚,大概7个多小时后,尝试回到这个话题,以获取其余的请求信息。我打赌是阻塞问题。我在我已经过时的桌面上尝试了更新,用原来的语句更新了200万行,花了大约4分钟。我是这个数据库的唯一用户。这不排除阻塞吗?没有触发器。解释结果在我编辑的帖子中。我想它把UDPATE和SELECT分开了?关于第二张桌子的好主意;我看看今天晚些时候是否可以试试。只是为了确保,你在更新之前写了删除索引的命令。这不会让事情变得更糟吗?更新后的字段A.X没有索引,我有涉及A.Y和A.Z的WHERE子句@ArenCambre:正如你看到的I.Y
我们的查询计划没有使用索引。之所以如此,是因为A.Y是非常不可选择的,甚至A.Z似乎是某个唯一的id也不会有帮助,因为您无论如何都要更新几乎完整的表。但我也怀疑,降低指数会对你有很大帮助。哦,哇,我明白你的意思了。我只是对另一个带有索引的表上的一个简单查询做了解释,我看到了在结果中明确提到索引的位置。我不清楚为什么索引不起作用。不管怎样,我已经将@maniek的答案标记为正确答案,因为他的最后一颗子弹似乎是最好的答案。我的赌注是阻塞问题。我在我已经过时的桌面上尝试了更新,用原来的语句更新了200万行,花了大约4分钟。我是这个数据库的唯一用户。这不排除阻塞吗?没有触发器。解释结果在我编辑的帖子中。我想它把UDPATE和SELECT分开了?关于第二张桌子的好主意;我看看今天晚些时候是否可以试试。只是为了确保,你在更新之前写了删除索引的命令。这不会让事情变得更糟吗?更新后的字段A.X没有索引,我有涉及A.Y和A.Z的WHERE子句@ArenCambre:正如你看到的,我没有使用索引。之所以如此,是因为A.Y是非常不可选择的,甚至A.Z似乎是某个唯一的id也不会有帮助,因为您无论如何都要更新几乎完整的表。但我也怀疑,降低指数会对你有很大帮助。哦,哇,我明白你的意思了。我只是对另一个带有索引的表上的一个简单查询做了解释,我看到了在结果中明确提到索引的位置。我不清楚为什么索引不起作用。不管怎样,我已经将@maniek的答案标记为正确答案,因为他的最后一颗子弹似乎是最好的答案。