删除索引锁

use*_*057 4 postgresql indexing locking

我的 Postgres 版本是 9.6

我今天尝试使用以下命令从数据库中删除索引:

drop index index_name;
Run Code Online (Sandbox Code Playgroud)

它导致了很多锁 - 整个应用程序被卡住,直到我杀死了 drop 的所有会话(为什么它被分成几个会话?)。

当我检查锁时,我发现几乎所有被阻止的会话都执行该查询:

SELECT a.attname, format_type(a.atttypid, a.atttypmod),
pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod    
FROM
pg_attribute a LEFT JOIN pg_attrdef d
                       ON a.attrelid = d.adrelid AND a.attnum = d.adnum
WHERE a.attrelid = <index_able_name>::regclass
AND a.attnum > 0 AND NOT a.attisdropped
ORDER BY a.attnum;
Run Code Online (Sandbox Code Playgroud)

这会阻止系统操作是否有意义?

所以我决定删除带有并发选项的索引以防止锁定。

drop index concurrently index_name;
Run Code Online (Sandbox Code Playgroud)

我现在从 PGAdmin 执行它(因为您无法从 noraml 事务运行它)。

跑了20多分钟,还没完。索引大小为 20MB+-。

当我检查数据库的锁时,我发现该表上有一个选择查询,这会阻止删除命令。

但是,当我进行此选择并在另一个会话中执行时,速度很快(2-3)秒。

那么为什么它会阻止我的下降呢?还有其他选择吗?也许要禁用索引?

Tom*_*zky 9

drop indexdrop index concurrently通常是非常快的命令,但它们与所有 DDL 命令一样,都需要对表进行独占访问。

它们的不同之处仅在于如何尝试实现这种独占访问权。Plaindrop index会简单地请求表上的独占锁。这将阻止在查询开始后尝试使用该表的所有查询(甚至选择)drop。它将执行此操作,直到获得排他锁 - 当所有以任何方式接触表的事务(在 drop 命令之前启动)将完成并且带有 a 的事务drop被提交时。这解释了为什么您的应用程序停止工作。

concurrently版本还需要短暂的独占访问权限。但它的工作方式不同 - 它不会阻塞表,而是等到没有其他查询触及它,然后执行其(通常是简短的)工作。但如果桌子一直很忙,它就永远找不到这样的时刻,并无限地等待它。另外我想它只是尝试每 X 毫秒重复锁定表直到成功,因此稍后的并行执行可能会更幸运并且更快完成。

如果您看到多个同时会话尝试删除索引,而您没有预料到会发生这种情况,那么您的应用程序中存在错误。数据库永远不会自行完成此操作。