首頁 > 軟體

mysql中如何檢視表是否被鎖問題

2023-02-22 06:01:09

如何檢視是否發生死鎖

在使用mysql的時候,如何檢視表是否被鎖呢?

檢視表被鎖狀態和結束死鎖步驟:

1.在mysql命令列執行sql語句

use dbName;  // 切換到具體資料庫
show engine innodb status;  // 查詢db是否發生死鎖

2.檢視資料表被鎖狀態

show OPEN TABLES where In_use > 0; 

該語句可以查詢到當前鎖表的狀態

3.分析鎖表的SQL

通過sql紀錄檔,分析相應SQL,給表加索引,常用欄位加索引,表關聯欄位加索引等方式對sql進行優化。

4.檢視正在鎖的事務

SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;

在5.5中,information_schema 庫中增加了三個關於鎖的表(innoDB引擎):

innodb_trx ## 當前執行的所有事務
innodb_locks ## 當前出現的鎖
innodb_lock_waits ## 鎖等待的對應關係

先來看一下這三張表結構:

root@127.0.0.1 : information_schema 13:28:38> desc innodb_locks;
+————-+———————+——+—–+———+——-+
| Field       | Type                | Null | Key | Default | Extra |
+————-+———————+——+—–+———+——-+
| lock_id     | varchar(81)         | NO   |     |         |       |#鎖ID
| lock_trx_id | varchar(18)         | NO   |     |         |       |#擁有鎖的事務ID
| lock_mode   | varchar(32)         | NO   |     |         |       |#鎖模式
| lock_type   | varchar(32)         | NO   |     |         |       |#鎖型別
| lock_table  | varchar(1024)       | NO   |     |         |       |#被鎖的表
| lock_index  | varchar(1024)       | YES  |     | NULL    |       |#被鎖的索引
| lock_space  | bigint(21) unsigned | YES  |     | NULL    |       |#被鎖的表空間號
| lock_page   | bigint(21) unsigned | YES  |     | NULL    |       |#被鎖的頁號
| lock_rec    | bigint(21) unsigned | YES  |     | NULL    |       |#被鎖的記錄號
| lock_data   | varchar(8192)       | YES  |     | NULL    |       |#被鎖的資料
+————-+———————+——+—–+———+——-+
10 rows in set (0.00 sec)
   
root@127.0.0.1 : information_schema 13:28:56> desc innodb_lock_waits;
+——————-+————-+——+—–+———+——-+
| Field             | Type        | Null | Key | Default | Extra |
+——————-+————-+——+—–+———+——-+
| requesting_trx_id | varchar(18) | NO   |     |         |       |#請求鎖的事務ID
| requested_lock_id | varchar(81) | NO   |     |         |       |#請求鎖的鎖ID
| blocking_trx_id   | varchar(18) | NO   |     |         |       |#當前擁有鎖的事務ID
| blocking_lock_id  | varchar(81) | NO   |     |         |       |#當前擁有鎖的鎖ID
+——————-+————-+——+—–+———+——-+
4 rows in set (0.00 sec)
   
root@127.0.0.1 : information_schema 13:29:05> desc innodb_trx ;
+—————————-+———————+——+—–+———————+——-+
| Field                      | Type                | Null | Key | Default             | Extra |
+—————————-+———————+——+—–+———————+——-+
| trx_id                     | varchar(18)         | NO   |     |                     |       |#事務ID
| trx_state                  | varchar(13)         | NO   |     |                     |       |#事務狀態:
| trx_started                | datetime            | NO   |     | 0000-00-00 00:00:00 |       |#事務開始時間;
| trx_requested_lock_id      | varchar(81)         | YES  |     | NULL                |       |#innodb_locks.lock_id
| trx_wait_started           | datetime            | YES  |     | NULL                |       |#事務開始等待的時間
| trx_weight                 | bigint(21) unsigned | NO   |     | 0                   |       |#
| trx_mysql_thread_id        | bigint(21) unsigned | NO   |     | 0                   |       |#事務執行緒ID
| trx_query                  | varchar(1024)       | YES  |     | NULL                |       |#具體SQL語句
| trx_operation_state        | varchar(64)         | YES  |     | NULL                |       |#事務當前操作狀態
| trx_tables_in_use          | bigint(21) unsigned | NO   |     | 0                   |       |#事務中有多少個表被使用
| trx_tables_locked          | bigint(21) unsigned | NO   |     | 0                   |       |#事務擁有多少個鎖
| trx_lock_structs           | bigint(21) unsigned | NO   |     | 0                   |       |#
| trx_lock_memory_bytes      | bigint(21) unsigned | NO   |     | 0                   |       |#事務鎖住的記憶體大小(B)
| trx_rows_locked            | bigint(21) unsigned | NO   |     | 0                   |       |#事務鎖住的行數
| trx_rows_modified          | bigint(21) unsigned | NO   |     | 0                   |       |#事務更改的行數
| trx_concurrency_tickets    | bigint(21) unsigned | NO   |     | 0                   |       |#事務並行票數
| trx_isolation_level        | varchar(16)         | NO   |     |                     |       |#事務隔離級別
| trx_unique_checks          | int(1)              | NO   |     | 0                   |       |#是否唯一性檢查
| trx_foreign_key_checks     | int(1)              | NO   |     | 0                   |       |#是否外來鍵檢查
| trx_last_foreign_key_error | varchar(256)        | YES  |     | NULL                |       |#最後的外來鍵錯誤
| trx_adaptive_hash_latched  | int(1)              | NO   |     | 0                   |       |#
| trx_adaptive_hash_timeout  | bigint(21) unsigned | NO   |     | 0                   |       |#
+—————————-+———————+——+—–+———————+——-+
22 rows in set (0.01 sec)

5.檢視等待鎖的事務

SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS.

6.檢視鎖的型別和狀態:

show status like '%lock%';

7.查詢程序

show processlist

8.殺死發生死鎖的程序

如果發生死鎖,通過該語句可以查詢到表被鎖的程序,然後通過kill命令殺掉該程序。

其他檢視表鎖的情況:

# 檢視表鎖的情況:
mysql> show status like 'table%';
+----------------------------+---------+
| Variable_name | Value |
+----------------------------+---------+
| Table_locks_immediate | 100 |
| Table_locks_waited | 11 |
+----------------------------+---------+

# 檢視InnoDB_row_lock狀態變數來分析系統上的行鎖的爭奪情況:
mysql> show status like 'InnoDB_row_lock%';
+-------------------------------+--------+
| Variable_name                 | Value  |
+-------------------------------+--------+
| Innodb_row_lock_current_waits | 0      |
| Innodb_row_lock_time          | 159372 |
| Innodb_row_lock_time_avg      | 39843  |
| Innodb_row_lock_time_max      | 51154  |
| Innodb_row_lock_waits         | 4      |
+-------------------------------+--------+
5 rows in set (0.01 sec)

mysql>

在分析innodb中鎖阻塞時,幾種方法的對比情況:

  • (1)使用show processlist檢視不靠譜;
  • (2)直接使用show engine innodb status檢視,無法判斷到問題的根因;
  • (3)使用mysqladmin debug檢視,能看到所有產生鎖的執行緒,但無法判斷哪個才是根因;
  • (4)開啟innodb_lock_monitor後,再使用show engine innodb status檢視,能夠找到鎖阻塞的根因。

死鎖發生情況及原因

產生原因

所謂死鎖:是指兩個或兩個以上的程序在執行過程中,因爭奪資源而造成的一種互相等待的現象。若無外力作用,它們都將無法推進下去。此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等待的程序稱為死鎖程序。表級鎖不會產生死鎖。所以解決死鎖主要還是針對於最常用的InnoDB。

死鎖的關鍵在於:兩個(或以上)的Session加鎖的順序不一致。

那麼對應的解決死鎖問題的關鍵就是:讓不同的session加鎖有次序

發生死鎖的幾種情況

會出現死鎖的幾種情況

我們有兩張結構一模一樣的表,分別為t1和t2:

id:integer	
token:varchar	
message:varchar

其中id是主鍵(自增),token是非聚集索引,message沒有索引。

1、一張表兩行記錄交叉申請互斥鎖

A執行到第二步時,等待B釋放第一步的鎖,而B需要執行完第二步結束事務之後才能釋放鎖;

B執行到第二步時,等待A釋放第一步的速,這樣A和B都無法進行下去,就產生了死鎖現象。

2、兩張表兩行記錄交叉申請互斥鎖

這種情況與1中的類似。

3、聚集索引與非聚集索引衝突

這種不一定會產生死鎖,表面上也看不出來。

假設A中滿足條件的記錄加鎖順序為(5,4,3,2,1),B中加鎖順序為(1,2,3,4,5),這裡的排序是對應record的主鍵;

(InnoDB的鎖是逐步獲取的,而不是一次獲取全部需要的鎖。)

有可能A加鎖了5和4,B加鎖了1、2、3,再往下進行的話就會出相互等待陷入僵局的情況,就是死鎖。

4、聚集索引衝突

這種情況與3中的類似。

5、間隙鎖衝突

這種情況是因為A第一步使用了間隙鎖,在A釋放鎖之前B第二步無法完成,也會形成死鎖。

innodb提供了wait-for graph演演算法來主動進行死鎖檢測,每當加鎖請求無法立即滿足需要並進入等待時,wait-for graph演演算法都會被觸發,檢測是否出現等待環路。

當檢測到死鎖時,InnoDB會選擇代價比較小的事務進行回滾。

總結

以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com