1. 等待事件介绍
在任意时间点,每一个数据库服务端进程,要么正忙于处理一个请求(busy),要么正在等待一个特定的事件发生(waiting)。我们说它处于忙的状态,意味着这个进程当时是需要使用CPU的。举例来说,一个会话进程在执行一个SQL过程时,可能正在进行一个算术计算,我们说它处于忙的状态,而不是等待状态。与此同时,另一个会话进程可能在提交事务,它在等待操作系统的响应,告诉它刷写日志时使用的fsync系统调用已经完成,这时我们说它处于等待状态。
虽然说等待事件是oracle的概念,但是实际上它在大多数关系型数据库里面都是存在的。不管你看得到,还是看不到,它都在那里。这是一个性能调优工作永远绕不开的话题。
2. 动态跟踪
PostgreSQL允许对数据库服务器进行动态跟踪。这样就允许在代码内特定的点上调用外部工具来跟踪执行过程。目前此功能主要目的是为了提供给数据库开发者使用,它要求使用者对代码非常熟悉。
3. PostgreSQL的等待事件
下面主要介绍3类等待事件:常规锁、轻量级锁和IO操作。这里只介绍相关的概念,对于观测等待事件的方法,可以通过PostgreSQL的动态跟踪机制,使用dtrace进行跟踪观测,也可以通过进行二次开发对相关的等待事件进行统计收集。
4. 等待事件:常规锁
4.1 常规锁介绍
锁的管理包括对不同粒度锁的操作,这些粒度包括表、内存页(目前只在索引中使用对内存页的加锁)、元组、事务、虚拟事务以及当前数据库中的其他对象。可以通过pg_locks视图观察当前数据库系统中的锁占用和等待的情况。
4.2 相关函数
LockAcquireResult LockAcquireExtended(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock, bool dontWait, bool reportMemoryError);
4.3 主要的内置跟踪点
probe lock__wait__start(unsigned int locktag_field1, unsigned int locktag_field2, unsigned int locktag_field3, unsigned int locktag_field4, unsigned int locktag_type, LOCKMODE lockmode);
probe lock__wait__done(unsigned int locktag_field1, unsigned int locktag_field2, unsigned int locktag_field3, unsigned int locktag_field4, unsigned int locktag_type, LOCKMODE lockmode);
4.4 常规锁相关的等待事件
(1) 表对象上的锁: 对表对象进行访问、修改、管理维护等操作时的锁操作
(2) 表对象上的扩展锁: 在对一个表进行页面扩展时的锁操作
(3) 表中页面上的锁: 对一个页面对象进行的加锁操作
(4) 元组上的锁: 对一个元组对象进行的加锁操作
(5) 事务上的锁: 一个事务在运行过程中,会保持一个和事务XID相关的锁,直到事务结束
(6) 虚拟事务上的锁: 一个事务在运行过程中,会保持一个和会话ID、本会话事务ID相关的锁,直到事务结束
(7) 一般的数据库对象上的锁: 对一般数据库对象进行的加锁操作
4.5 常规锁的模式和用途
(1) AccessShareLock: SELECT
(2) RowShareLock: SELECT FOR UPDATE/FOR SHARE
(3) RowExclusiveLock: INSERT, UPDATE, DELETE
(4) ShareUpdateExclusiveLock: VACUUM (non-FULL),ANALYZE, CREATE INDEX CONCURRENTLY
(5) ShareLock: CREATE INDEX (WITHOUT CONCURRENTLY)
(6) ShareRowExclusiveLock: like EXCLUSIVE MODE, but allows ROW SHARE
(7) ExclusiveLock: blocks ROW SHARE/SELECT...FOR UPDATE
5. 等待事件:轻量级锁
5.1 轻量级锁介绍
轻量级锁主要提供对共享存储器的数据结构的互斥访问。这些数据结构包括页面缓冲区、日志缓冲区、缓冲区管理结构、会话状态、事务状态以及数据库中的其他内部数据结构。
5.2 相关函数
static inline bool LWLockAcquireCommon(LWLock *l, LWLockMode mode, uint64 *valptr, uint64 val);
5.3 主要的内置跟踪点
probe lwlock__acquire(const char *name, int id, LWLockMode mode);
probe lwlock__release(const char *name, int id);
probe lwlock__wait__start(const char *name, int id, LWLockMode mode);
probe lwlock__wait__done(const char *name, int id, LWLockMode mode);
5.4 轻量级锁相关的等待事件
(1) Bufffer Content Lock
描述: 访问缓冲区中的页面时的相关加锁操作
场景说明: 多个并发事务同时对同一个数据页面进行访问时会发生争用
(2) Buffer Freelist Lock
描述: 访问页面缓冲区空闲链表的相关加锁操作
场景说明: 数据库启动时,大量事务并发访问数据会出现对该锁的争用
(3) Process Array Lock
描述: 访问会话和事务状态列表的相关加锁操作
场景说明: 大量并发的短事务会出现对该锁的争用
(4) WAL Insert Lock
描述: 向XLOG缓冲区插入日志时的加锁操作
场景说明: 大量事务并发修改数据会出现对该锁的争用
(5) WAL Write Lock
描述: 将XLOG缓冲区中的日志写入文件时的加锁操作
场景说明: 大量事务并发修改数据会出现对该锁的争用,可考虑组提交
(6) CLog Control Lock
描述: 在Clog缓冲区中设置和访问事务状态时的加锁操作
场景说明: 大量并发的短事务会出现对该锁的争用
(7) Subtrans Control Lock
描述: 在子事务日志缓冲区中设置和访问事务状态时的加锁操作
场景说明: 大量子事务会出现对该锁的争用,比如SQL过程中循环执行BEGIN … EXCEPTION语句块的情况,应该尽量避免
(8) MultiXact Offset Control Lock、MultiXact Member Control Lock
描述: 在组合事务日志缓冲区中设置和访问事务状态时的加锁操作
场景说明: 多个事务对相同数据并发执行SELECT FOR SHARE时会出现对该锁的争用
(9) Two Phase State Lock
描述: 设置和访问两阶段事务状态时的加锁操作
场景说明: 在分布式环境中,大量并发的两阶段事务会出现该锁的争用
6. 等待事件:IO操作
6.1 IO操作介绍
IO操作是指对文件进行访问或者通过网络进行收发的操作,这些文件包括表、索引、临时表、临时数据文件、XLOG日志文件、事务状态文件、运行日志文件和配置文件等。
6.2 主要的函数
void smgrwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer, bool skipFsync);
void smgrread(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer);
6.3 几个主要的内置跟踪点
probe buffer__read__start(ForkNumber forkNum, BlockNumber blockNum, Oid spcNode, Oid dbNode, Oid relNode, int backend, bool isExtend);
probe buffer__read__done(ForkNumber forkNum, BlockNumber blockNum, Oid spcNode, Oid dbNode, Oid relNode, int backend, bool isExtend, bool);
probe buffer__flush__start(ForkNumber forkNum, BlockNumber blockNum, Oid spcNode, Oid dbNode, Oid relNode);
probe buffer__flush__done(ForkNumber forkNum, BlockNumber blockNum, Oid spcNode, Oid dbNode, Oid relNode);
6.4 IO操作相关的等待事件
(1) base或global目录下文件
描述: 访问表进行相关操作时的IO事件
(1) pgsql_tmp目录下文件
描述: 执行查询过程中进行排序或散列操作时访问临时文件产生的IO事件
(2) pg_stat_tmp目录下文件
描述: 更新和读取临时的统计信息时的IO事件
(3) pg_tblspc目录下文件
描述: 访问用户自定义表空间下的表进行相关操作时的IO事件
(4) pg_xlog目录下文件
描述: 修改数据时写XLOG日志的IO事件,或者主备机进行日志传输时产生的IO事件
(5) pg_clog目录下文件
描述: 设置和访问事务状态时的IO事件
(6) pg_log目录下文件
描述: 记录运行时日志产生的IO事件
(7) pg_twophase目录下文件
描述: 设置和访问两阶段事务状态时的IO事件
(8) pg_subtrans目录下文件
描述: 设置和访问子事务状态时的IO事件
(9) pg_multixact目录下文件
描述: 设置和访问组合事务状态时的IO事件
(10) 网络套接字
描述: 通过网络发送查询和接收结果时产生的IO事件