一:檢查是否鎖表, 查詢進(jìn)程并殺死進(jìn)程
在堯都等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供成都做網(wǎng)站、成都網(wǎng)站設(shè)計(jì) 網(wǎng)站設(shè)計(jì)制作定制網(wǎng)站開發(fā),公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),高端網(wǎng)站設(shè)計(jì),成都全網(wǎng)營銷,成都外貿(mào)網(wǎng)站建設(shè)公司,堯都網(wǎng)站建設(shè)費(fèi)用合理。
1) 查詢是否鎖表
show open tables where in_use 0;
2) 查詢進(jìn)程(如果您有SUPER權(quán)限,您可以看到所有線程。否則,您只能看到您自己的線程)
show processlist;
二:查看在鎖事務(wù),殺死事務(wù)對應(yīng)的線程ID
1) 查看正在鎖的事務(wù)
select * from information_schema.INNODB_LOCKS;
2) 殺死進(jìn)程id(就是[select * from information_schema.INNODB_LOCKS; ]命令的trx_mysql_thread_id列)
kill 線程ID
3) 查看等待鎖的事務(wù)
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;
其它:
1) 查看服務(wù)器狀態(tài)
show status like '%lock%';
2) 查看超時(shí)時(shí)間:
show variables like '%timeout%';
1.查看表被鎖狀態(tài)
2.查看造成死鎖的sql語句
3.查詢進(jìn)程
4.解鎖(刪除進(jìn)程)
5.查看正在鎖的事物? (8.0以下版本)
6.查看等待鎖的事物?(8.0以下版本)
查看MySQL數(shù)據(jù)庫的死鎖日志
1. 使用終端或命令提示符登錄到MySQL,輸入命令:mysql -h xxxx.xxx.xxx -P 3306 -u username -p?解釋:xxxx.xxx.xxx是數(shù)據(jù)庫IP地址,username是數(shù)據(jù)庫用戶名,輸入命令后,會讓你輸入username對應(yīng)的密碼,就可以登錄了
2. 如何查看MySQL數(shù)據(jù)庫的死鎖信息?在MySQL客戶端下輸入命令:?show engine innodb status \G;
3. 如何定位MySQL數(shù)據(jù)庫的死鎖信息?在打印出來的信息中找到“LATEST DETECTED DEADLOCK”一節(jié)內(nèi)容,看圖中紅線
4. 如何分析日志,定位死鎖原因?看3里面的圖,紫色劃線部分?分析:?事務(wù)1,等待?RECORD LOCKS space id 553 page no 376 n bits 368 index `index_user_id` of table `tbj`.`score_user`,這個(gè)位置的X鎖?事務(wù)2,持有?RECORD LOCKS space id 553 page no 376 n bits 368 index `index_user_id` of table `tbj`.`score_user`這個(gè)地方的S鎖?事務(wù)2,等待這個(gè)地方的X鎖?理論上這個(gè)事務(wù)2是可以提交的不會,死鎖,但是這個(gè)事務(wù)日志只打印最后一部分死鎖,信息,這里面隱含的條件是,事務(wù)1也持有?RECORD LOCKS space id 553 page no 376 n bits 368 index `index_user_id` of table `tbj`.`score_user`這個(gè)地方的S鎖,這樣,事務(wù)2不能加X鎖,同時(shí)事務(wù)1也不能加X鎖,產(chǎn)生死鎖。
方法1:利用 metadata_locks 視圖
此方法僅適用于 MySQL 5.7 以上版本,該版本 performance_schema 新增了 metadata_locks,如果上鎖前啟用了元數(shù)據(jù)鎖的探針(默認(rèn)是未啟用的),可以比較容易的定位全局鎖會話。
方法2:利用 events_statements_history 視圖此方法適用于 MySQL 5.6 以上版本,啟用 performance_schema.eventsstatements_history(5.6 默認(rèn)未啟用,5.7 默認(rèn)啟用),該表會 SQL 歷史記錄執(zhí)行,如果請求太多,會自動清理早期的信息,有可能將上鎖會話的信息清理掉。
方法3:利用 gdb 工具如果上述兩種都用不了或者沒來得及啟用,可以嘗試第三種方法。利用 gdb 找到所有線程信息,查看每個(gè)線程中持有全局鎖對象,輸出對應(yīng)的會話 ID,為了便于快速定位,我寫成了腳本形式。也可以使用 gdb 交互模式,但 attach mysql 進(jìn)程后 mysql 會完全 hang 住,讀請求也會受到影響,不建議使用交互模式。
方法4:show processlist
如果備份程序使用的特定用戶執(zhí)行備份,如果是 root 用戶備份,那 time 值越大的是持鎖會話的概率越大,如果業(yè)務(wù)也用 root 訪問,重點(diǎn)是 state 和 info 為空的,這里有個(gè)小技巧可以快速篩選,篩選后嘗試 kill 對應(yīng) ID,再觀察是否還有 wait global read lock 狀態(tài)的會話。
方法5:重啟試試!
當(dāng)你開始執(zhí)行一個(gè) ALTER ,而你遇到了可怕的“元數(shù)據(jù)鎖定等待”,我敢肯定你一定遇見過。我最近遇到了一個(gè)案例,其中被更改的表要執(zhí)行一個(gè)很小范圍的更新(100行)。ALTER 在負(fù)載測試期間一直等待了幾個(gè)小時(shí)。在停止負(fù)載測試后,ALTER 按預(yù)期在不到一秒的時(shí)間內(nèi)就完成了。那么這里發(fā)生了什么?
檢查外鍵
每當(dāng)有奇數(shù)次鎖定時(shí),我的第一直覺就是檢查外鍵。當(dāng)然這張表有一些外鍵引用了一個(gè)更繁忙的表。但是這種行為似乎仍然很奇怪。對表運(yùn)行 ALTER 時(shí),會針對子表請求一個(gè) SHARED_UPGRADEABLE 元數(shù)據(jù)鎖。還有針對父級的 SHARED_READ_ONLY 元數(shù)據(jù)鎖。
我們來看看如何根據(jù)文檔獲取元數(shù)據(jù)鎖定[1]:
如果給定鎖定有多個(gè)服務(wù)器,則首先滿足最高優(yōu)先級鎖定請求,并且與 max_write_lock_count系統(tǒng)變量有關(guān)。寫鎖定請求的優(yōu)先級高于讀取鎖定請求。
[1]:
請務(wù)必注意鎖定順序是序列化的:語句逐個(gè)獲取元數(shù)據(jù)鎖,而不是同時(shí)獲取,并在此過程中執(zhí)行死鎖檢測。
通常在考慮隊(duì)列時(shí)考慮先進(jìn)先出。如果我發(fā)出以下三個(gè)語句(按此順序),它們將按以下順序完成:
1. INSERT INTO parent2. ALTER TABLE child3. INSERT INTO parent
但是當(dāng)子 ALTER 語句請求對父進(jìn)行讀取鎖定時(shí),盡管排序,但兩個(gè)插入將在 ALTER 之前完成。以下是可以演示此示例的示例場景:
數(shù)據(jù)初始化:
CREATE TABLE `parent` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`val` varchar(10) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE `child` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`parent_id` int(11) DEFAULT NULL,
`val` varchar(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_parent` (`parent_id`),
CONSTRAINT `fk_parent` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB;
INSERT INTO `parent` VALUES (1, "one"), (2, "two"), (3, "three"), (4, "four");
Session 1:
start transaction;update parent set val = "four-new" where id = 4;
Session 2:
alter table child add index `idx_new` (val);
Session 3:
start transaction;update parent set val = "three-new" where id = 3;
此時(shí),會話 1 具有打開的事務(wù),并且處于休眠狀態(tài),并在父級上授予寫入元數(shù)據(jù)鎖定。 會話 2 具有在子級上授予的可升級(寫入)鎖定,并且正在等待父級的讀取鎖定。最后會話 3 具有針對父級的授權(quán)寫入鎖定:
mysql select * from performance_schema.metadata_locks;+-------------+-------------+-------------------+---------------+-------------+| OBJECT_TYPE | OBJECT_NAME | LOCK_TYPE ? ? ? ? | LOCK_DURATION | LOCK_STATUS |+-------------+-------------+-------------------+---------------+-------------+| TABLE ? ? ? | child ? ? ? | SHARED_UPGRADABLE | TRANSACTION ? | GRANTED ? ? | - ALTER (S2)| TABLE ? ? ? | parent ? ? ?| SHARED_WRITE ? ? ?| TRANSACTION ? | GRANTED ? ? | - UPDATE (S1)| TABLE ? ? ? | parent ? ? ?| SHARED_WRITE ? ? ?| TRANSACTION ? | GRANTED ? ? | - UPDATE (S3)| TABLE ? ? ? | parent ? ? ?| SHARED_READ_ONLY ?| STATEMENT ? ? | PENDING ? ? | - ALTER (S2)+-------------+-------------+-------------------+---------------+-------------+
請注意,具有掛起鎖定狀態(tài)的唯一會話是會話 2(ALTER)。會話 1 和會話 3 (分別在 ALTER 之前和之后發(fā)布)都被授予了寫鎖。排序失敗的地方是在會話 1 上發(fā)生提交的時(shí)候。在考慮有序隊(duì)列時(shí),人們會期望會話 2 獲得鎖定,事情就會繼續(xù)進(jìn)行。但是,由于元數(shù)據(jù)鎖定系統(tǒng)的優(yōu)先級性質(zhì),會話 3 具有鎖定,會話 2 仍然等待。
如果另一個(gè)寫入會話進(jìn)入并啟動新事務(wù)并獲取針對父表的寫鎖定,則即使會話 3 完成,ALTER 仍將被阻止。
只要我保持一個(gè)對父表打開元數(shù)據(jù)鎖定的活動事務(wù),子表上的 ALTER 將永遠(yuǎn)不會完成。更糟糕的是,由于子表上的寫鎖定成功(但是完整語句正在等待獲取父讀鎖定),所以針對子表的所有傳入讀取請求都將被阻止!
另外,請考慮一下您通常如何對無法完成的語句進(jìn)行故障排除。您查看已經(jīng)打開較長時(shí)間的事務(wù)(在進(jìn)程列表和 InnoDB 狀態(tài)中)。但由于阻塞線程現(xiàn)在比 ALTER 線程更年輕,因此您將看到的最舊的事務(wù)/線程是 ALTER 。
這正是這種情況下發(fā)生的情況。在準(zhǔn)備發(fā)布時(shí),我們的客戶端正在運(yùn)行 ALTER 語句并結(jié)合負(fù)載測試(一種非常好的做法?。┮源_保順利發(fā)布。問題是負(fù)載測試保持對父表打開一個(gè)活動的寫事務(wù)。這并不是說它只是一直在寫,而是有多個(gè)線程,一個(gè)總是活躍的。 這阻止了 ALTER 完成并阻止對相對靜態(tài)的子表的隨后的讀請求。
幸運(yùn)的是,這個(gè)問題有一個(gè)解決方案(除了從設(shè)計(jì)模式中驅(qū)逐外鍵)。變量?max_write_lock_count[2]?可用于允許在寫入鎖定之后在讀取鎖定之前授予讀取鎖定連續(xù)寫鎖。默認(rèn)情況下,此變量設(shè)置為 18446744073709551615,如果你對該表發(fā)出 10,000 次寫入/秒,那么你的讀將被鎖定 5800 萬年……
第一步,查出已鎖的進(jìn)程
查看正在鎖的事務(wù)
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
``
查看等待鎖的事務(wù)
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;
``
INNODB_TRX表主要是包含了正在InnoDB引擎中執(zhí)行的所有事務(wù)的信息,包括waiting for a lock和running的事務(wù)
select * from information_schema.innodb_trx
``
第二步,kill進(jìn)程
show engin innodb status; //最后一次死鎖信息及sql
show open tables where in_use 0 //查看鎖表