您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關如何查看MySQL鎖等待的原因的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
--sys庫的介紹
mysql 5.6也可以有sys庫(基于performance_schema的視圖)。sys庫是一個開源項目,在githup上早就有,是一個DBA的開源工具,后來mysql感覺好,就放在了mysql5.7上。
下載地址:https://github.com/mysql/mysql-sys
[tms@m-db3 ~]$ cd mysql-sys-master
[tms@m-db3 ~]$ mysql < sys_56.sql
這樣,就可以在mysql5.6里面加入sys庫了,不過mysql 5.6只有88張表,而mysql 5.7有101張,這是因為Mysql 5.7的performace_schema庫里面又多了幾張表。
sys庫是performance_schema的視圖。
--MySQL鎖等待
當Mysql發生鎖等待情況時,可以通過如下語句來在線查看:
mysql> select * from sys.innodb_lock_waits \G; *************************** 1. row *************************** wait_started: 2018-07-16 16:25:17 //鎖等待開始的時間,16:25開始等待 wait_age: 00:10:08 //發現問題時已經等待了10分鐘了 wait_age_secs: 608 //608秒,也就是等10分鐘了 locked_table: `iws`.`busi_reconciliationgbgsinfo_inputdetails` //被鎖住的表名 locked_index: PRIMARY //被鎖住的索引 locked_type: RECORD //鎖的類型為行鎖 waiting_trx_id: 13666265 //waiting transaction id,正在等待事務的id號 waiting_trx_started: 2018-07-16 16:24:54 //這個事務是從16:24開始等待 waiting_trx_age: 00:10:31 //等了10分鐘了 waiting_trx_rows_locked: 1 //正在等待的這個事務鎖住了1行記錄 waiting_trx_rows_modified: 0 //正在等待的這個事務修改了0行記錄 waiting_pid: 441805 //這個等待事務的線程id是多少,通過show processlist 命令可以查到它,結果看到是一個sleep的線程,沒有執行具體sql語句,見下 waiting_query: update busi_reconciliationgbgs ... where id = 4510 //等待鎖釋放的語句 waiting_lock_id: 13666265:2924:21:94 //正在等待的鎖id waiting_lock_mode: X //等待鎖的類型是排它鎖 blocking_trx_id: 13666259 //這個事務id阻塞了waiting lock blocking_pid: 441803 阻塞事務的pid blocking_query: NULL //阻塞事務的sql語句 blocking_lock_id: 13666259:2924:21:94 blocking_lock_mode: X blocking_trx_started: 2018-07-16 16:24:51 blocking_trx_age: 00:10:34 blocking_trx_rows_locked: 1 blocking_trx_rows_modified: 1 sql_kill_blocking_query: KILL QUERY 441803 sql_kill_blocking_connection: KILL 441803 1 row in set (0.00 sec) ERROR: No query specified
上面看到輸出了很多的東西,看的我都蒙圈了。后來查看mysql官方文檔,慢慢的才發現,其實只關注上面的waiting_pid、waiting_query和blocking_pid、blocking_query四個參數即可;其中waiting_pid和blocking_pid兩個參數就是通過執行show processlist命令里面輸出的線程id號,如下:
mysql> show full processlist \G; *************************** 8. row *************************** Id: 441803 User: iws Host: 172.16.21.7:46121 db: iws Command: Sleep Time: 655 State: Info: NULL *************************** 9. row *************************** Id: 441805 User: iws Host: 172.16.21.7:46122 db: iws Command: Query Time: 652 State: updating Info: update busi_reconciliationgbgsinfo_inputdetails set bgs_id = 1622 , date = '2018-06-24 00:00:00' , awbnumber = '006-85516771' , incidental = 15.00 , entry_exit = 23.00 , warehousing_fee = 0.00 , loading_unloading = 0.00 , other = 0.00 , total = 38.00 , state = 20 , comparison_resultsid = 30 , confirmation_method = '人工' , confirmationid = 'root' , confirmationtime = '2018-07-16 16:25:17' , confirmation_note = '.' , createtime = '2018-06-24 20:00:07' , createrid = '9862ebdbaf3249a88bcaa8f01bde0471' where id = 4510
通過上面兩個的輸出結果,我們明白了,是441803線程鎖住了表,造成線程441805的等待。
我們看到發生等待的線程441805對應的sql語句是:update busi_reconciliationgbgs ... where id = 4510,但是鎖表的線程441803對應的sql語句竟然是Null。這就更讓人迷惑了。
于是我默默的翻開了ysql官方文檔,原來里面已經對這個null專門做了說明。
官方文檔說,要想找到這個null值對應的阻塞語句,可以通過下面幾個步驟尋找:
a)、根據鎖表的processlist id 441803,運用如下sql,找到null對應的sql語句,如下:
SELECT SQL_TEXT FROM performance_schema.events_statements_current WHERE THREAD_ID in (SELECT THREAD_ID FROM performance_schema.threads WHERE PROCESSLIST_ID=441803)
b)、如果上面找到的sql語句,你還是不能分析出為什么他們會鎖表,一直拿著鎖不釋放,那么你可以查看 performance_schema.events_statements_history表里面最近執行過的10條sql(假設上面查到的thread_id=28):
SELECT EVENT_ID,CURRENT_SCHEMA, SQL_TEXT FROM performance_schema.events_statements_history WHERE THREAD_ID in (SELECT THREAD_ID FROM performance_schema.threads WHERE PROCESSLIST_ID=441803) order by event_id
其他:
上面查詢鎖的sql可以只關注已下幾個列,如下:
SELECT wait_started, wait_age, waiting_pid, waiting_query, blocking_trx_id, blocking_pid, blocking_query, blocking_lock_mode, sql_kill_blocking_query FROM sys.innodb_lock_waits
~~~~~~~~~~~~分割線~~~~~~~~~~~~~~~~~
最近我用python 2.6寫了個自動殺鎖的腳本,只要發現sys.innodb_lock_waits表里面有鎖表的內容,就殺死相應的sql線程,并輸出殺死sql的內容到當前目錄下:
#!/usr/bin/env python #-*-coding:utf8-*- #下載rpm包安裝,下載地址:https://dev.mysql.com/downloads/connector/python/,注意mysql-connector-python版本需要是1.1.17的,2.x的版本運行會有問題 from __future__ import print_function import mysql.connector as mdb import os #全局變量 username = 'root' password = '' hostname = 'localhost' database = 'sys' #配置信息 config = { 'user': username, 'password': password, 'host': hostname, 'database': database } #定義函數,查看鎖表的行數 def Get_sys_lock(): show_locked_num = "select count(*) from sys.innodb_lock_waits" cursor.execute(show_locked_num) for i in cursor: locked_sql_num = i[0] return locked_sql_num #定義函數,如果有鎖表,就重定向到locked_sql.txt文件里面 def show_locked_sql(): count = 0 count1 = 0 #如果日志文件存在就刪除 if os.path.isfile('locked_sql.txt'): os.remove('locked_sql.txt') if os.path.isfile('null_sql.txt'): os.remove('null_sql.txt') if os.path.isfile('last_10_null_sql.txt'): os.remove('last_10_null_sql.txt') #引用函數 locked_sql_num = Get_sys_lock() print("鎖表的行數是:{0}".format(locked_sql_num)) if locked_sql_num > 0: #如果有鎖表 show_locked_sql = " SELECT \ wait_started, \ wait_age, \ waiting_pid, \ waiting_query, \ blocking_trx_id, \ blocking_pid, \ blocking_query, \ blocking_lock_mode, \ sql_kill_blocking_query \ FROM \ sys.innodb_lock_waits \ " cursor.execute(show_locked_sql) for i in cursor: wait_started = i[0] wait_age = i[1] waiting_pid = i[2] waiting_query = i[3] blocking_trx_id = i[4] blocking_pid = i[5] blocking_query = i[6] blocking_lock_mode = i[7] sql_kill_blocking_query = i[8] if not str(blocking_query).strip(): #如果blocking_query字符串為Null #import pdb;pdb.set_trace() show_null_sql = "SELECT SQL_TEXT FROM performance_schema.events_statements_current WHERE THREAD_ID in (SELECT THREAD_ID FROM performance_schema.threads WHERE PROCESSLIST_ID=%s)" % blocking_pid conn = mdb.connect(**config) cursor1 = conn.cursor() cursor1.execute(show_null_sql) #print(cursor1.fetchall()) for j in cursor1: SQL_TEXT = j[0] print(SQL_TEXT) cursor1.close try: count1 += 1 f = open('null_sql.txt','a') #a表示追加 f.write ( '##########' + 'The ' + str(count1) + ' rows ' + 'Blocking null query對應的具體sql為##########\n' + 'blocking_pid: ' + str(blocking_pid) + '\n' 'sql_text: ' + str(SQL_TEXT) + '\n\n' ) except OSError as reason: print('出錯了:' + str(reason)) finally: f.close #再查看null對應的最后10條sql show_last_10_null_sql = "SELECT EVENT_ID,CURRENT_SCHEMA, SQL_TEXT FROM performance_schema.events_statements_history WHERE THREAD_ID in (SELECT THREAD_ID FROM performance_schema.threads WHERE PROCESSLIST_ID=%s) order by event_id" % blocking_pid cursor2 = conn.cursor() cursor2.execute(show_last_10_null_sql) cursor2.close #print(cursor1.fetchall()) count2 = 0 for j in cursor2: EVENT_ID = j[0] CURRENT_SCHEMA = j[1] SQL_TEXT = j[2] try: count2 += 1 f = open('last_10_null_sql.txt','a') #a表示追加 f.write ( '##########' + 'The ' + str(count2) + ' rows ' + 'laster blocking null query對應的具體sql為##########\n' + 'blocking_pid: ' + str(blocking_pid) + '\n' 'EVENT_ID: ' + str(EVENT_ID) + '\n' 'CURRENT_SCHEMA: ' + str(CURRENT_SCHEMA) + '\n' 'SQL_TEXT: ' + str(SQL_TEXT) + '\n\n' ) except OSError as reason: print('出錯了:' + str(reason)) finally: f.close #把鎖表的情況重定向到一個locked_sql.txt文件里面 try: count += 1 f = open('locked_sql.txt','a') #a表示追加 f.write('##########' + 'The ' + str(count) + ' rows' + '###########\n') f.write ( 'wait_started: ' + str(wait_started) + '\n' + 'wait_age: ' + str(wait_age) + '\n' + 'waiting_pid: ' + str(waiting_pid ) + '\n' + 'waiting_query: ' + str(waiting_query) + '\n' + 'blocking_trx_id: ' + str(blocking_trx_id) + '\n' + 'blocking_pid: ' + str(blocking_pid) + '\n' + 'blocking_query: ' + str(blocking_query) + '\n' + 'blocking_lock_mode: ' + str(blocking_lock_mode) + '\n' + 'sql_kill_blocking_query: ' + str(sql_kill_blocking_query) + '\n\n' ) ''' f.write ( '##########' + 'Blocking null query對應的具體sql為##########\n' + 'blocking_pid:' + str(blocking_pid) + 'sql_text:' + str(SQL_TEXT) ) ''' except OSError as reason: print('出錯了:' + str(reason)) finally: f.close #定義函數,列出當前所有執行的sql線程 def show_processlist(): count = 0 #如果日志文件存在就刪除 if os.path.isfile('show_processlist.txt'): os.remove('show_processlist.txt') #引用函數 locked_sql_num = Get_sys_lock() #print("鎖表的行數是:{0}".format(locked_sql_num)) if locked_sql_num > 0: #如果有鎖表 show_processlist = "select \ id, \ user, \ host, \ db, \ time, \ state, \ info \ from information_schema.`PROCESSLIST` order by time desc \ " cursor.execute(show_processlist) for i in cursor: id = i[0] user = i[1] host = i[2] db = i[3] time = i[4] state = i[5] info = i[6] #把鎖表的情況重定向到一個show_processlist.txt文件里面 try: count += 1 f = open('show_processlist.txt','a') #a表示追加 f.write('##########' + 'The ' + str(count) + ' rows' + '###########\n') f.write ( 'id: ' + str(id) + '\n' + 'user: ' + str(user) + '\n' + 'host: ' + str(host) + '\n' + 'db: ' + str(db) + '\n' + 'time: ' + str(time) + '\n' + 'state: ' + str(state) + '\n' + 'info: ' + str(info) + '\n\n' ) except OSError as reason: print('出錯了:' + str(reason)) finally: f.close #定義函數,如果有鎖表,就殺死 def kill_locked_sql(): #引用函數 locked_sql_num = Get_sys_lock() #print("鎖表的行數是:{0}".format(locked_sql_num)) if locked_sql_num > 0: #如果有鎖表 execute_locked_sql = " SELECT \ sql_kill_blocking_query \ FROM \ sys.innodb_lock_waits \ " cursor.execute(execute_locked_sql) for i in cursor: sql_kill_blocking_query = i[0] conn = mdb.connect(**config) cursor1 = conn.cursor() try: cursor1.execute(sql_kill_blocking_query) except: print('出錯了') cursor1.close #主程序 conn = mdb.connect(**config) cursor = conn.cursor() show_locked_sql() show_processlist() kill_locked_sql() cursor.close conn.close
感謝各位的閱讀!關于“如何查看MySQL鎖等待的原因”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。