记录下Mysql外键引发的锁等待Lock wait timeout exceeded; try restarting transaction

最近突然有个项目后台老是报Lock wait timeout exceeded; try restarting transaction,导致一些功能不可用。。。

mysql>  SELECT * FROM information_schema.INNODB_TRX;
+----------+-----------+---------------------+-----------------------+---------------------+------------+---------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+-------------------+-------------------+------------------+-----------------------+-----------------+-------------------+-------------------------+---------------------+-------------------+------------------------+----------------------------+---------------------------+---------------------------+------------------+----------------------------+
| trx_id   | trx_state | trx_started         | trx_requested_lock_id | trx_wait_started    | trx_weight | trx_mysql_thread_id | trx_query                                                                                                                                                                                                           | trx_operation_state | trx_tables_in_use | trx_tables_locked | trx_lock_structs | trx_lock_memory_bytes | trx_rows_locked | 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 | trx_is_read_only | trx_autocommit_non_locking |
+----------+-----------+---------------------+-----------------------+---------------------+------------+---------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+-------------------+-------------------+------------------+-----------------------+-----------------+-------------------+-------------------------+---------------------+-------------------+------------------------+----------------------------+---------------------------+---------------------------+------------------+----------------------------+
| 96756605 | LOCK WAIT | 2019-12-11 15:36:26 | 96756605:793:7:170    | 2019-12-11 15:36:26 |          2 |             2321332 | INSERT INTO OS_WFENTRY (ID, NAME, STATE) VALUES (1084,'107',0)                                                                                                                                                      | inserting           |                 1 |                 1 |                2 |                  1136 |               1 |                 0 |                       0 | READ COMMITTED      |                 1 |                      1 | NULL                       |                         0 |                         0 |                0 |                          0 |
| 96752553 | LOCK WAIT | 2019-12-11 15:30:08 | 96752553:793:7:170    | 2019-12-11 15:36:56 |          4 |             2321206 | INSERT INTO OS_CURRENTSTEP (ID,ENTRY_ID, STEP_ID, ACTION_ID, OWNER, START_DATE, DUE_DATE, FINISH_DATE, STATUS, CALLER ) VALUES (2105, 1084, 11, null, '4', '2019-12-11 15:29:17.677', null, null, 'Underway', null) | inserting           |                 1 |                 2 |                3 |                  1136 |               9 |                 1 |                       0 | READ COMMITTED      |                 1 |                      1 | NULL                       |                         0 |                         0 |                0 |                          0 |
| 96751789 | RUNNING   | 2019-12-11 15:29:17 | NULL                  | NULL                |        110 |             2321203 | NULL                                                                                                                                                                                                                | NULL                |                 0 |                11 |              101 |                 24784 |               8 |                 9 |                       0 | READ COMMITTED      |                 1 |                      1 | NULL                       |                         0 |                         0 |                0 |                          0 |
+----------+-----------+---------------------+-----------------------+---------------------+------------+---------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+-------------------+-------------------+------------------+-----------------------+-----------------+-------------------+-------------------------+---------------------+-------------------+------------------------+----------------------------+---------------------------+---------------------------+------------------+----------------------------+
3 rows in set (0.00 sec)

通过查询锁表语句,能够知道程序里确实锁表了,但是跟代码发现逻辑上也没有什么问题,但就是每次锁表后手动kill进程后,隔几个小时又会出现这种情况。在debug跟代码的时候发现应该是先执行OS_WFENTRY的插入,但是通过上面的sql看出是OS_CURRENTSTEP 的插入先执行的,由于OS_CURRENTSTEP 的外键是OS_WFENTRY表的主键id,但是在OS_CURRENTSTEP 执行的时候,OS_WFENTRY还没执行所以就产生了等待的现象,将主外键关系删除后不再出现锁表,锁等待事件,记录下如果有锁等待超时问题可以先看下是否有主外键关系。
(转)

外键的好处:可以使得两张表关联,保证数据的一致性和实现一些级联操作。保持数据一致性,完整性,主要目的是控制存储在外键表中的数据。 使两张表形成关联,外键只能引用外表中的列的值!可以使得两张表关联,保证数据的一致性和实现一些级联操作;

一般数据库属于持久层,尽量把业务逻辑转移到应用层,外键会使表之间耦合太大,所以建议靠程序去检测和数据库的事务来保证数据的完整性和一致性;另外外键需要额外的资源进行数据完整性和一致性检验,更容易造成死锁,数据库更容易达到瓶颈,特别是表的扩展能力大大受限。

innoDB 是目前mysql中唯一支持外键的内置存储引擎。使用外键是需要成本的,比如外键通常都要求每次在修改数据时都要在另一张表中多执行一次查询操作。虽然innoDB强制外键使用索引,但还是无法消除这种约束检查的开销。如果外键列的选择性很低,则会导致一个非常大的且选择性很低的索引。

不过在某些场景下,外键回提升一些性能。如果想要确保两个相关的表始终有一致的数据,那么使用外键要比应用程序中检查一致性的性能要高的多,此外,外键在相关数据的更新和删除上,要比应用中维护要更高效,不过,外键维护操作是逐步进行的,所以这样的更新要比批量的更新和删除要慢一些

外键约束会需要一些额外的锁。容易导致死锁。而且这类死锁问题很难排查。

外键会带来很大的额外消耗。对性能有很大的影响。

posted @ 2019-12-20 22:57  叶落无蝉鸣  阅读(121)  评论(0编辑  收藏  举报