从 postgres 中的大表中删除大列

问题描述 投票:0回答:1

我在 postgres 数据库中有一个非常大的表(超过 TB 空间),并且它有一个文本列,该文本列也很大,导致数据库中出现 TOASTING。 当我尝试删除该列时,它会在 20 分钟后超时。该列没有索引

我正在尝试使用下面的代码删除它:

ALTER TABLE a DROP COLUMN b;

我收到一条错误消息,指出该语句由于超时而被取消。

SQL Error [57014]: ERROR: canceling statement due to statement timeout

怎样才能加快柱子的下降速度?

我尝试增加statement_timeout,但即使在30分钟后它仍然超时

database postgresql vacuum
1个回答
0
投票

该查询应该几乎立即可以工作,因为它只隐藏该列,而不会尝试执行任何删除它的实际工作。 来自

ALTER TABLE
文档

DROP COLUMN
形式不会物理删除列,而只是使其对SQL操作不可见。表中的后续插入和更新操作将为该列存储空值。因此,删除列很快,但不会立即减少表的磁盘大小,因为删除的列占用的空间不会被回收。随着现有行的更新,空间将随着时间的推移而被回收。

如果在其上设置了分区和/或继承,除非您

ALTER TABLE
ONLY
a DROP COLUMN b;
,否则它将尝试级联整个结构。在这种情况下,只需将其放在父级上,然后处理所有后代。与此列的外键引用类似的故事,如果有的话:您可能想要一一删除这些 FK 列,然后删除这一列,而无需
CASCADE

您没有明确排除这些,所以我只是确定 - 如果您有分区,我想您会提到它,并且 FK 不太可能出现在长文本列上。它还需要一个

unique
约束,该约束会自动创建一个索引来强制执行它——你确实说过该列上没有索引。

除此之外,请检查

pg_locks
和/或
pg_stat_activity
看看是什么阻碍了您。
ALTER TABLE
所做的第一件事是请求并等待锁定:

请注意,每个子表单所需的锁定级别可能有所不同。除非明确说明,否则将获取

ACCESS EXCLUSIVE
锁。

因此,它可能坐在那里,盯着一群会话在该表上执行某些操作,等待它们完成,而新查询开始与任何其他锁定请求一起在其后面排队。这也意味着您可能需要查看

auto_explain
,看看谁有足够的耐心等待您退出,谁可能在经常超时失败的查询上浪费您的资源。如果你等了30分钟才拿到锁,这意味着有人已经持有它30分钟了。值得一看,但更有可能的是,您正在处理的长事务持有锁的时间比它们需要的时间长,而其中的单个语句都不需要那么长时间。

要查找阻塞会话,您可以使用 PostgreSQL Wiki 中的示例:

SELECT blocked_locks.pid     AS blocked_pid,
       blocked_activity.usename  AS blocked_user,
       blocking_locks.pid     AS blocking_pid,
       blocking_activity.usename AS blocking_user,
       blocked_activity.query    AS blocked_statement,
       blocking_activity.query   AS current_statement_in_blocking_process
FROM  pg_catalog.pg_locks         blocked_locks
JOIN pg_catalog.pg_stat_activity blocked_activity  
  ON blocked_activity.pid = blocked_locks.pid
JOIN pg_catalog.pg_locks         blocking_locks 
  ON blocking_locks.locktype = blocked_locks.locktype
AND blocking_locks.database IS NOT DISTINCT FROM blocked_locks.database
AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
AND blocking_locks.pid != blocked_locks.pid
JOIN pg_catalog.pg_stat_activity blocking_activity 
  ON blocking_activity.pid = blocking_locks.pid
WHERE NOT blocked_locks.granted;

如果你不耐烦,你可以诉诸

pg_cancel_backend()
甚至
pg_terminate_backend()

© www.soinside.com 2019 - 2024. All rights reserved.