7

我一直在对包含 3 个索引的 2.5 亿行的表运行更新;此 UPDATE 使用另一个包含 3000 万行的表。它已经运行了大约 36 个小时。我想知道他们是否是一种了解它距离完成有多近的方法,如果它计划花费一百万天来完成它,我会杀了它;但是,如果它只需要一两天,我会让它运行。这是命令查询:

UPDATE pagelinks SET pl_to = page_id
    FROM page
    WHERE 
        (pl_namespace, pl_title) = (page_namespace, page_title)
        AND
        page_is_redirect = 0
;

EXPLAIN 不是这里的问题,我只提到大表有多个索引,以便在某种程度上证明更新它需要多长时间。但无论如何,这里是解释:

Merge Join  (cost=127710692.21..135714045.43 rows=452882848 width=57)
  Merge Cond: (("outer".page_namespace = "inner".pl_namespace) AND ("outer"."?column4?" = "inner"."?column5?"))
  ->  Sort  (cost=3193335.39..3219544.38 rows=10483593 width=41)
        Sort Key: page.page_namespace, (page.page_title)::text
        ->  Seq Scan on page  (cost=0.00..439678.01 rows=10483593 width=41)
              Filter: (page_is_redirect = 0::numeric)
  ->  Sort  (cost=124517356.82..125285665.74 rows=307323566 width=46)
        Sort Key: pagelinks.pl_namespace, (pagelinks.pl_title)::text"
        ->  Seq Scan on pagelinks  (cost=0.00..6169460.66 rows=307323566 width=46)

现在我还发送了一个并行查询命令,以删除页面链接的索引之一;当然它正在等待更新完成(但我还是想尝试一下!)。因此,我不能从页面链接中选择任何内容,因为害怕破坏数据(除非您认为终止 DROP INDEX postmaster 进程是安全的?)。

所以我想知道他们是否是一个可以跟踪死元组数量的表或其他东西。很高兴知道 UPDATE 在完成其任务时有多快或多远。

Thx(PostgreSQL 没有我想象的那么智能;它需要启发式)

4

3 回答 3

6

您是否阅读了“使用说明”的 PostgreSQL 文档来解释您显示的输出?

我不是普通的 PostgreSQL 用户,但我只是阅读了该文档,然后与EXPLAIN您显示的输出进行了比较。您的UPDATE查询似乎没有使用索引,并且它被迫进行表扫描以对page和进行排序pagelinks。毫无疑问,该排序足够大,需要临时磁盘文件,我认为这些文件是在您的temp_tablespace.

然后我看到估计读取的数据库页面。EXPLAIN该输出的顶层显示(cost=127710692.21..135714045.43). 这里的单元在磁盘 I/O 访问中。因此,它将访问磁盘超过 1.35 亿次来执行此操作UPDATE

请注意,即使是 10,000rpm 的磁盘,寻道时间为 5 毫秒,在最佳条件下也最多可以达到每秒 200 次 I/O 操作。这意味着您UPDATE将需要 188 小时(7.8 天)的磁盘 I/O,即使您可以在此期间维持饱和的磁盘 I/O(即连续读取/写入没有中断)。这是不可能的,而且我预计实际吞吐量至少会下降一个数量级,尤其是因为您毫无疑问同时在使用此服务器进行各种其他工作。所以我猜你只是通过你的UPDATE.

如果是我,我会在第一天杀死这个查询,然后找到另一种UPDATE更好地利用索引并且不需要磁盘排序的方法。您可能无法在单个 SQL 语句中执行此操作。

至于你的DROP INDEX,我猜它只是阻塞,等待对表的独占访问,当它处于这种状态时,我认为你可能会杀死它。

于 2009-01-09T18:55:32.527 回答
3

这已经很老了,但是如果您想要一种方法来监视您的更新...请记住,序列会受到全局影响,因此您只需创建一个以在另一个会话中监视此更新,只需执行以下操作:

create sequence yourprogress; 

UPDATE pagelinks SET pl_to = page_id
    FROM page
    WHERE 
        (pl_namespace, pl_title) = (page_namespace, page_title)
        AND
        page_is_redirect = 0 AND NEXTVAL('yourprogress')!=0;

然后在另一个会话中执行此操作(不要担心事务,因为序列会受到全局影响):

select last_value from yourprogress;

这将显示有多少行受到影响,因此您可以估计需要多长时间。

在刚刚结束时重新启动您的序列以再次尝试:

alter sequence yourprogress restart with 1;

或者干脆放弃它:

drop sequence yourprogress;
于 2018-09-20T11:09:59.547 回答
0

您需要索引,或者正如比尔指出的那样,它需要对所有表进行顺序扫描。

CREATE INDEX page_ns_title_idx on page(page_namespace, page_title);
CREATE INDEX pl_ns_title_idx on pagelink(pl_namespace, pl_title);
CREATE INDEX page_redir_idx on page(page_is_redirect);
于 2009-01-09T19:13:19.900 回答