PostgreSQL锁表排查方法及索引相关注意事项

一 排查锁表问题

1.判断被锁的是哪张表,获取其pid相关信息,将任务回滚

查询是否锁表

select oid from pg_class where relname = '可能被锁了的表'

select pid from pg_locks where relation = '上面查询出来的pid'

如果有查询结果,则表示该表被锁,则需要释放这个锁定,下面这条语句会取消当前的执行语句,并回滚

select pg_cancel_backend(上面查询到的pid)

pg_class

名字 类型 引用 描述
relname name 表、索引、视图等的名字。
relnamespace oid pg_namespace.oid 包含这个关系的名字空间(模式)的 OID
reltype oid pg_type.oid 对应这个表的行类型的数据类型(索引为零,它们没有 pg_type 记录)。
relowner oid pg_authid.oid 关系所有者
relam oid pg_am.oid 如果行是索引,那么就是所用的访问模式(B-tree, hash 等等)
relfilenode oid 这个关系在磁盘上的文件的名字,如果没有则为 0
reltablespace oid pg_tablespace.oid 这个关系存储所在的表空间。如果为零,则意味着使用该数据库的缺省表空间。如果关系在磁盘上没有文件,则这个字段没有什么意义。
relpages int4 以页(大小为 BLCKSZ)的此表在磁盘上的形式的大小。它只是规划器用的一个近似值,是由 VACUUM, ANALYZE 和几个 DDL 命令,比如 CREATE INDEX 更新。
reltuples float4 表中行的数目。只是规划器使用的一个估计值,由 VACUUM, ANALYZE 和几个 DDL 命令,比如 CREATE INDEX 更新。
reltoastrelid oid pg_class.oid 与此表关联的 TOAST 表的 OID ,如果没有为 0 。TOAST 表在一个从属表里"离线"存储大字段。
reltoastidxid oid pg_class.oid 对于 TOAST 表是它的索引的 OID ,如果不是 TOAST 表则为 0
relhasindex bool 如果它是一个表而且至少有(或者最近有过)一个索引,则为真。它是由 CREATE INDEX 设置的,但 DROP INDEX 不会立即将它清除。如果 VACUUM 现一个表没有索引,那么它将清理 relhasindex
relisshared bool 如果该表在整个集群中由所有数据库共享则为真。只有某些系统表(比如 pg_database)是共享的。
relkind char r = 普通表, i = 索引, S = 序列, v = 视图, c = 复合类型, t = TOAST 表
relnatts int2 关系中用户字段数目(除了系统字段以外)。在 pg_attribute 里肯定有相同数目对应行。又见 pg_attribute.attnum
relchecks int2 表里的检查约束的数目;参阅 pg_constraint
reltriggers int2 表里的触发器的数目;参阅 pg_trigger
relukeys int2 未使用(不是唯一值的数目)
relfkeys int2 未使用(不是表中外键的数目)
relrefs int2 未使用
relhasoids bool 如果为关系中每行都生成一个 OID 则为真
relhaspkey bool 如果这个表有一个(或者曾经有一个)主键,则为真。
relhasrules bool 如表有规则就为真;参阅 pg_rewrite
relhassubclass bool 如果有(或者曾经有)任何继承的子表,为真。
relfrozenxid xid 该表中所有在这个之前的事务 ID 已经被一个固定的(“frozen”)事务 ID 替换。这用于跟踪该表是否需要为了防止事务 ID 重叠或者允许收缩 pg_clog 而进行清理。如果该关系不是表则为零(InvalidTransactionId)。
relacl aclitem[] 访问权限。参阅 GRANTREVOKE 获取详细信息。
reloptions text[] 访问方法特定的选项,使用"keyword=value"格式的字符串

pg_locks

名称 类型 引用 描述
locktype text 可锁对象的类型: relation, extend, page, tuple, transactionid, virtualxid, object, userlock, or advisory
database oid pg_database.oid 锁目标存在的数据库的OID,如果目标是一个共享对象则为0,如果目标是一个事务ID则为空
relation oid pg_class.oid 作为锁目标的关系的OID,如果目标不是一个关系或者只是关系的一部分则此列为空
page integer 作为锁目标的页在关系中的页号,如果目标不是一个关系页或元组则此列为空
tuple smallint 作为锁目标的元组在页中的元组号,如果目标不是一个元组则此列为空
virtualxid text 作为锁目标的事务虚拟ID,如果目标不是一个虚拟事务ID则此列为空
transactionid xid 作为锁目标的事务ID,如果目标不是一个事务ID则此列为空ID
classid oid pg_class.oid 包含锁目标的系统目录的OID,如果目标不是一个普通数据库对象则此列为空
objid oid 任意OID列 锁目标在它的系统目录中的OID,如果目标不是一个普通数据库对象则为空
objsubid smallint 锁的目标列号(classidobjid指表本身),如果目标是某种其他普通数据库对象则此列为0,如果目标不是一个普通数据库对象则此列为空
virtualtransaction text 保持这个锁或者正在等待这个锁的事务的虚拟ID
pid integer 保持这个锁或者正在等待这个锁的服务器进程的PID,如果此锁被一个预备事务所持有则此列为空
mode text 此进程已持有或者希望持有的锁模式
granted boolean 如果锁已授予则为真,如果锁被等待则为假
fastpath boolean 如果锁通过快速路径获得则为真,通过主锁表获得则为假

2.根据异常判断锁类型,根据具体的业务逻辑排查是哪个位置出现了问题。

比如遇到了行锁,顺着更新的语句,看里面的执行逻辑,一步一步排查。我遇到的问题就是update里面有select语句,在进行select的时候没有落到索引上,导致查询特别慢,添加索引或者根据实际业务处理一下即可。

二 explain和explain analyze

explain sql:只是查询语句的执行计划

explain analyze sql:分析语句的执行计划并真正的执行SQL语句

三 单列索引,联合索引的区别

在线上服务中,随着表数据量的增加,加索引是家常便饭,添加索引可以极大的提升我们的查询效率。首先我们以一张表为例:

表名:user

列名:id, name, age, phone,birthday,address

单列索引:只建立一列的索引,比如在name上建立索引

联合索引:使用多列建立索引,比如(name, age,address)

原则:

最左原则,从左为起点的任何连续索引都可以匹配得上。按照可扩展性的原则,通常我们会把查询最频繁的条件放在最左面,这样的话,当我们需要扩展为联合索引时就非常方便。

重点:

1.当我们存在多个单列索引时,只会生效第一个索引。这就是为什么我们需要联合索引的原因。

eg:我们有单列索引(name),(age),(adress),当我们的查询语句为where name=‘XXX’ and age=18的时候,只会走(name)索引。但是呢我们经常需要对name,age等的联合查询,这个时候如果有(name,age)的联合索引,那么查询就会落在(name, age)上。

2.创建(name, age,address)联合索引时,相当于创建了(name)单列索引,(name,age)联合索引及(name,age,address)联合索引。但是如果我们查询时使用where name=‘XXX’ and address='XXX’时,最终走的为(name)单列索引。

3.数据量不大的话,不建议增加索引,因为建立索引本身也需要一定的开销,反而得不偿失。

4.如果查询语句中使用的是OR连接符,索引不生效。

5.联合索引通常要比建立多个索引更有优势,因为索引越多其实占用的磁盘空间会越大,在数据更新的时候会更慢。但是,我们建立好联合索引后,查询的顺序就非常关键了,能严格按照顺序进行查询的话,我们的查询效率会更高。

你可能感兴趣的:(PostgreSQL,PostgreSQL,锁表,索引,查询分析器,联合索引)