一、CommitLog文件做什么的¶
PostgreSQL把事务状态记录在CommitLog中 从PostgreSQL10版本开始,CLOG文件是在pg_xact子目录下
前面也介绍过事务的状态有以下4种
TRANSACTION_STATUS_IN_PROGRESS=0x00:表示事务正在进行中。 TRANSACTION_STATUS_COMMITTED=0x01:表示事务已提交。 TRANSACTION_STATUS_ABORTED=0x02:表示事务已回滚。 TRANSACTION_STATUS_SUB_COMMITTED=0x03:表示子事务已提交
CommitLog文件是一个位图文件,因为事务有上述4种状态,所以需要用两位来表示一个事务的状态,所以 CommitLog有如下的特点
理论上数据库最多记录20亿个事务
以CommitLog最多占用512MB空间
CommitLog也会被VACUUM清理,什么时候清理,参数“autovacuum_freeze_max_age”的默认设置为2亿的控制,
问题:既然CommitLog文件 是记录事务提交的状态
那如果每读到一行时都需要判断这一行 上的xmin和xmax代表的事务是否已提交或回滚,因而都去读CommitLog文件,这样效率会不会很低?
优化:
-
PostgreSQL对CommitLog文件进行了Cache,即在共享内存中有clog buffer
-
每行上有一个标志字段“t_infomask”,如果标志位“HEAP_XMIN_COMMITTED”被设置就知道xmin代表的 事务已提交,则不需要到CommitLog文件中去判断
二、事务ID¶
事务ID是一个32bit长的数字,总是有可能会被消耗完的,消耗完之后会重新从头开始分配, 但是这样也有一个问题:
这些旧的事务ID已经被分配过,如果重新分配,需要先把旧的事务ID回收。而原先分配的旧事务是写 到每个表中每一行的xmin或xmax字段上的,这样就会导致有事务id冲突问题,
此工作是由VACUUM动作来完成的,如果行上的xmin是较旧的事务ID
如果VACUUM清理不及时,会有什么问题: pg会提前做一个判断,因为事务ID放到一个环上, 如果最新分配的事务ID与最早的事务ID之间的距 离还有1千万时,数据库会在日志中告警:
WARNING: database "XXX" must be vacuumed within 177009986 transactions HINT: To avoid a database shutdown, execute a database- wide VACUUM in "XXX".
如果还不处理?
最新分配的事务ID与最早的事务ID之间的距离还 有1百万时,数据库会宕机,同时在日志文件中打印以下错误日志:
ERROR: database is not accepting commands to avoid wraparound data loss in database "XXXX"
所以这里针对第一个警告,需要最好做一个报警,以防因此导致数据库宕机