在PostgreSQL中,使用TRUNCATE命令清理表数据,或使用DROP TABLE删除表时,可能出现磁盘空间未立即释放的问题。本文将介绍该现象的原因,并提供排查和解决方法。
问题原因
PostgreSQL执行TRUNCATE和DROP TABLE操作时,系统会在事务提交时对每一个要删除的文件进行unlink调用。unlink调用会解除inode的引用,但是如果此时有其他进程打开了该文件,文件的内容将会保留在磁盘上,磁盘空间不会立即回收。只有当满足以下条件之一时,系统才会释放磁盘空间:
终止所有打开了需要删除文件的进程。
打开文件的进程中,对文件描述符(file descriptor,fd)进行了close调用来关闭对应文件。
如果在执行TRUNCATE和DROP TABLE之前已经有连接打开了表文件,并且该连接在TRUNCATE和DROP TABLE执行后一直处于空闲(idle)状态,那么由于这个连接仍然持有对原始文件的打开引用,实际的磁盘空间不会立即被释放。
解决方案
在出现执行TRUNCATE或DROP TABLE命令后未释放磁盘空间的问题时,可以采用以下方法进行解决。
清理所有空间的连接。
SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE state='idle' AND backend_type='client backend';
在自建数据库场景中,需要找到已经打开但已被unlink的文件的进程,并终止这些连接。
在目标数据库服务器上执行lsof命令,查找已经被删除但仍被进程打开的文件。
lsof +L1
执行如下SQL,终止对应连接。
SELECT pg_terminate_backend(pid);
其中参数pid是要终止会话的进程ID。
文档内容是否对您有帮助?