我在 postgres 数据库中有一个非常大的表(超过 TB 空间),并且它有一个文本列,该文本列也很大,导致数据库中出现 TOASTING。 当我尝试删除该列时,它会在 20 分钟后超时。该列没有索引
我正在尝试使用下面的代码删除它:
ALTER TABLE a DROP COLUMN b;
我收到一条错误消息,指出该语句由于超时而被取消。
SQL Error [57014]: ERROR: canceling statement due to statement timeout
怎样才能加快柱子的下降速度?
我尝试增加statement_timeout,但即使在30分钟后它仍然超时
该查询应该几乎立即可以工作,因为它只隐藏该列,而不会尝试执行任何删除它的实际工作。 来自
ALTER TABLE
文档:
形式不会物理删除列,而只是使其对SQL操作不可见。表中的后续插入和更新操作将为该列存储空值。因此,删除列很快,但不会立即减少表的磁盘大小,因为删除的列占用的空间不会被回收。随着现有行的更新,空间将随着时间的推移而被回收。DROP COLUMN
如果在其上设置了分区和/或继承,除非您
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()
。