PostgreSQL逻辑备份, 指通过pg_dump或者直接调用COPY进行的备份方法.
一般来说, PostgreSQL 使用pg_dump备份数据库时, 会
1. 开启一个repeatable read事务,
2. 然后需要从系统表以及传入的参数, 生成备份集,
3. 备份开始前, 需要一次性把需要备份的所有对象都加上access share lock, 这个锁与DML不冲突, 只和DDL冲突, 例如TRUNCATE表会和pg_dump发生冲突(当需要备份的表被执行DDL时, 只要pg_dump未结束, DDL就会处于等待状态).
所以如果需要备份的数据集很大的话, 备份程序pg_dump持有access share lock的时间就越长, 这段时间如果程序需要对备份的表做出DDL操作(如drop, truncate), DDL SQL就要进入等待.
同样的道理, 如果系统正在跑比较长的事务或函数, 并且事务或函数中使用了表的DDL, 例如truncate. 那么备份这些表也将被堵塞知道长事务或函数结束.
这样的情况其实很容易发生, 例如凌晨是比较空闲的时间, 备份和统计作业可能都会放到凌晨来处理.
假设1点开始备份, 备份到5点结束. 备份作业包含了以下truncate操作的表.
2点的时候开始一个统计作业, 统计函数里面如果用到truncate操作的话, 这个操作可能要等到5点才能获得锁而继续下去.
这种场景的备份需要排除需要truncate的表, 那么就不会发生锁冲突.
pg_dump有一个参数来排除不需要备份的表.
-T, --exclude-table=TABLE do NOT dump the named table(s)
另外还有一个参数, 指定锁等待时间, 当pg_dump不能在这个时间内获得access share lock的话, 就报错.
--lock-wait-timeout=timeout
Do not wait forever to acquire shared table locks at the beginning of the dump. Instead fail if unable
to lock a table within the specified timeout. The timeout may be specified in any of the formats
accepted by SET statement_timeout. (Allowed values vary depending on the server version you are dumping
from, but an integer number of milliseconds is accepted by all versions since 7.3. This option is
ignored when dumping from a pre-7.3 server.)