问题:

有一个表需要增加字段,执行sql时一直在等待.长期阻塞

查看实例列表

> select * from information_schema.processlist
185270    root    192.168.10.66:60156    jpos-agent    Query    0    executing    /* ApplicationName=DBeaver 24.1.2 - SQLEditor <Script-9.sql> */ select * from information_schema.processlist
LIMIT 0, 200
185226    xpos_xst    192.168.10.181:57810    xpos_xst    Sleep    1154        
185228    xpos_xst    192.168.10.181:57854    xpos_xst    Sleep    1137        
185285    xpos_xst    192.168.10.181:60198    xpos_xst    Sleep    513        

查看innodb_locks表是否有锁

select * from information_schema.INNODB_LOCKS;

字段说明:
lock_id:锁 ID。
lock_trx_id:拥有锁的事务 ID。可以和 INNODB_TRX 表 JOIN 得到事务的详细信息。
lock_mode:锁的模式。有如下锁类型:行级锁包括:S、X、IS、IX,分别代表:共享锁、排它锁、意向共享锁、意向排它锁。表级锁包括:S_GAP、X_GAP、IS_GAP、IX_GAP 和 AUTO_INC,分别代表共享间隙锁、排它间隙锁、意向共享间隙锁、意向排它间隙锁和自动递增锁。
lock_type:锁的类型。RECORD 代表行级锁,TABLE 代表表级锁。
lock_table:被锁定的或者包含锁定记录的表的名称。
lock_index:当 LOCK_TYPE=’RECORD’ 时,表示索引的名称;否则为 NULL。
lock_space:当 LOCK_TYPE=’RECORD’ 时,表示锁定行的表空间 ID;否则为 NULL。
lock_page:当 LOCK_TYPE=’RECORD’ 时,表示锁定行的页号;否则为 NULL。
lock_rec:当 LOCK_TYPE=’RECORD’ 时,表示一堆页面中锁定行的数量,亦即被锁定的记录号;否则为 NULL。
lock_data:当 LOCK_TYPE=’RECORD’ 时,表示锁定行的主键;否则为NULL。

查看innodb_locks_waits表是否锁等待

select * from information_schema.INNODB_LOCK_WAITS;

字段说明:
requesting_trx_id:请求事务的 ID。
requested_lock_id:事务所等待的锁定的 ID。可以和 INNODB_LOCKS 表 JOIN。
blocking_trx_id:阻塞事务的 ID。
blocking_lock_id:某一事务的锁的 ID,该事务阻塞了另一事务的运行。可以和 INNODB_LOCKS 表 JOIN。

查看innodb_trx表查看是否有事务记录

select * from information_schema.INNODB_TRX;

字段说明:
trx_id:事务ID。
trx_state:事务状态,有以下几种状态:RUNNING、LOCK WAIT、ROLLING BACK 和 COMMITTING。
trx_started:事务开始时间。
trx_requested_lock_id:事务当前正在等待锁的标识,可以和 INNODB_LOCKS 表 JOIN 以得到更多详细信息。
trx_wait_started:事务开始等待的时间。
trx_weight:事务的权重。
trx_mysql_thread_id:事务线程 ID,可以和 PROCESSLIST 表 JOIN。
trx_query:事务正在执行的 SQL 语句。
trx_operation_state:事务当前操作状态。
trx_tables_in_use:当前事务执行的 SQL 中使用的表的个数。
trx_tables_locked:当前执行 SQL 的行锁数量。
trx_lock_structs:事务保留的锁数量。
trx_lock_memory_bytes:事务锁住的内存大小,单位为 BYTES。
trx_rows_locked:事务锁住的记录数。包含标记为 DELETED,并且已经保存到磁盘但对事务不可见的行。
trx_rows_modified:事务更改的行数。
trx_concurrency_tickets:事务并发票数。
trx_isolation_level:当前事务的隔离级别。
trx_unique_checks:是否打开唯一性检查的标识。
trx_foreign_key_checks:是否打开外键检查的标识。
trx_last_foreign_key_error:最后一次的外键错误信息。
trx_adaptive_hash_latched:自适应散列索引是否被当前事务锁住的标识。
trx_adaptive_hash_timeout:是否立刻放弃为自适应散列索引搜索 LATCH 的标识。

查看锁等待详情信息

show engine innodb status;

解决问题:

innodb锁结构

不论是表锁还是行锁,都是在事务执行过程中生成的,哪个事务生成了这个锁结构,这里就记录这个事务的信息。

此锁所在的事务信息在内存结构中只是一个指针,通过指针可以找到内存中关于该事务的更多信息,比方说事务id等。

mysql8.0锁信息表变更

MySQL8.0删除了information_schema.INNODB_LOCKS,添加了performance_schema.data_locks ,可以通过performance_schema.data_locks查看事务的锁情况,和MySQL5.7及之前不同,performance_schema.data_locks不但可以看到阻塞该事务的锁,还可以看到该事务所持有的锁。

同时,information_schema.INNODB_LOCK_WAITS也被performance_schema.data_lock_waits 所代替。

1.发现问题有一个事务一直running状态

#查询会话列表
select * from information_schema.processlist where id = [trx_mysql_thread_id]

#服务器上排查问题
netstat -nlatp | grep pid
ps -eaf | grep pid

#mysql控制台杀掉会话
kill [trx_mysql_thread_id] 命令杀掉这条事务线程

2.行锁分析

mysql> show status like 'innodb_row_lock%';
Innodb_row_lock_current_waits: 当前正在等待锁定的数量
Innodb_row_lock_time: 从系统启动到现在锁定总时间长度 (重要) 单位:毫秒 ms。
Innodb_row_lock_time_avg: 每次等待所花平均时间 (重要) 单位:毫秒 ms。
Innodb_row_lock_time_max:从系统启动到现在等待最长的一次所花时间 单位:毫秒 ms。
Innodb_row_lock_waits:系统启动后到现在总共等待的次数 (重要)

3.表锁分析

mysql> show status like 'table_lock%';
Table_locks_immediate:产生表级锁定的次数; 
Table_locks_waited:出现表级锁定争用而发生等待的次数;

优化建议

  • 尽可能在所有数据检索都通过索引来完成,避免无索引行锁升级为表锁

  • 合理设计索引,尽量缩小锁的范围

  • 尽可能较少检索条件,避免间隙锁

  • 尽量控制事务大小,减少锁定资源量和时间长度

  • 尽可能低级别事务隔离

文章作者: 刘同学
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 刘同学的小站
数据库 oracle Mysql
喜欢就支持一下吧