在执行DDL语句前,一定要记得设置锁超时时间。
DDL语句会申请access exclusive锁,access exclusive锁是最强的排它锁,在获得锁前,要求该表上没有任何会话访问;同时,DDL语句会阻塞任何对表的操作。例如:drop table、truncate、reindex、vacuum full、部分alter table等等。
由于DDL语句在获得锁前,要求该表上没有任何会话访问,如果有长事务、长时间执行的SQL访问表,那么需要等待这些会话执行完成后才能获得access exclusive锁。在等锁的过程中,DDL语句会阻塞该表上所有DDL语句后面执行的SQL,包括SELECT。如果该表有高并发SQL语句,那么将会导致大量的SQL语句被阻塞,进而导致数据库连接数迅速增长、服务器CPU打满,严重影响业务。
可以通过设置锁超时解决此问题,锁超时设置一般可以使用如下3种方式,影响范围各不相同,超时时间推荐30~60s:
当前会话生效(即时生效):
teledb=# set lock_timeout to '30s';
用户默认锁超时(设置之后,新建的连接才会生效):
teledb=# alter role teledb set lock_timeout to '30s';
数据库默认锁超时(设置之后,新建的连接才会生效):
teledb=# alter database teledb set lock_timeout to '30s';
注意lock_timeout参数是获取锁的超时时间,不止对DDL语句生效,对DML、DQL也生效;因此用户、数据库级默认锁超时间参数不应设置过小,设置过小可能会导致正常的DML、DQL语句超时,尤其并发业务量大,业务高峰期间,可能会因为锁超时设置过小导致大面积SQL语句超时报错。