Mysql鎖和死結分析

來源:互聯網
上載者:User

標籤:

  在MySQL中,行級鎖並不是直接鎖記錄,而是鎖索引。索引分為主鍵索引和非主鍵索引兩種,如果一條sql語句操作了主鍵索引,MySQL就會鎖定這條主鍵索引;如果一條語句操作了非主鍵索引,MySQL會先鎖定該非主鍵索引,再鎖定相關的主鍵索引。

在UPDATE、DELETE操作時,MySQL不僅鎖定WHERE條件掃描過的所有索引記錄,而且會鎖定相鄰的索引值(update時的set),即所謂的next-key locking。

案例分析1:

tab_test 結構如下:

id:主鍵;

state:狀態;

time:時間;

索引:idx_1(state,time)

出現死結的2條sql語句

update tab_test set state=1064,time=now() where state=1061 and time < date_sub(now(), INTERVAL 30 minute)update tab_test set state=1067,time=now () where id in (9921180)

原因分析:

  當“update tab_test set state=1064,time=now() where state=1061 and time < date_sub(now(), INTERVAL 30 minute)”執行時,MySQL會使用idx_1索引,因此首先鎖定相關的索引記錄,因為idx_1是非主鍵索引,為執行該語句,MySQL還會鎖定主鍵索引。

  假設“update tab_test set state=1067,time=now () where id in (9921180)”幾乎同時執行時,本語句首先鎖定主鍵索引,由於需要更新state的值,所以還需要鎖定idx_1的某些索引記錄。

  這樣第一條語句鎖定了idx_1的記錄,等待主鍵索引,而第二條語句則鎖定了主鍵索引記錄,而等待idx_1的記錄,這樣死結就產生了。

在第一條語句給主鍵加鎖前,第二條語句已經給主鍵加了鎖,所以在高並發的資料操作時,死結的情況就容易產生

InnoDB 會自動檢測一個事務的死結並復原一個或多個事務來防止死結。Innodb會選擇代價比較小的交易回復,此次事務(1)解鎖並復原,語句(2)繼續運行直至事務結束。

解決辦法

拆分第一條sql,先查出合格主索引值,再按照主鍵更新記錄:

select id from tab_test where state=1061 and time < date_sub(now(), INTERVAL 30 minute);update tab_test state=1064,time=now() where id in(......);

案例分析2

teamUser表的表結構如下:
PRIMARY KEY (`uid`,`Id`),
KEY `k_id_titleWeight_score` (`Id`,`titleWeight`,`score`),
ENGINE=InnoDB

出現死結的2條sql語句

insert into teamUser_20110121 select * from teamUserDELETE FROM teamUser WHERE teamId=$teamId AND titleWeight<32768 AND joinTime<‘$daysago_1week‘

兩語句加鎖情況
在innodb預設的交易隔離等級下,普通的SELECT是不需要加行鎖的,但LOCK IN SHARE MODE、FOR UPDATE及高序列化層級中的SELECT都要加鎖。有一個例外,此案例中,語句(1)insert into teamUser_20110121 select * from teamUser會對錶teamUser_20110121(ENGINE= MyISAM)加表鎖,並對teamUser表所有行的主鍵索引(即聚簇索引)加共用鎖定。預設對其使用主鍵索引。
而語句(2)DELETE FROM teamUser WHERE teamId=$teamId AND titleWeight<32768 AND joinTime<‘$daysago_1week‘為刪除操作,會對選中行的主鍵索引加獨佔鎖定。由於此語句還使用了非聚簇索引KEY `k_teamid_titleWeight_score` (`teamId`,`titleWeight`,`score`)的首碼索引,於是,還會對相關行的此非聚簇索引加獨佔鎖定。
鎖衝突的產生
由於共用鎖定與獨佔鎖定是互斥的,當一方擁有了某行記錄的獨佔鎖定後,另一方就不能其擁有共用鎖定,同樣,一方擁有了其共用鎖定後,另一方也無法得到其獨佔鎖定。所 以,當語句(1)、(2)同時運行時,相當於兩個事務會同時申請某相同記錄行的鎖資源,於是會產生鎖衝突。由於兩個事務都會申請主鍵索引,鎖衝突只會發生 在主鍵索引上。

避免死結的方法
InnoDB給MySQL提供了具有提交,復原和崩潰恢複能力的事務安全(ACID相容)儲存引擎。InnoDB鎖定在行級並且也在SELECT語句提供非鎖定讀。這些特色增加了多使用者部署和效能。
但其行鎖的機制也帶來了產生死結的風險,這就需要在應用程式設計時避免死結的發生。以單個SQL語句組成的隱含交易來說,建議的避免死結的方法如下:
1.如果使用insert…select語句備份表格且資料量較大,在單獨的時間點操作,避免與其他sql語句爭奪資源,或使用select into outfile加上load data infile代替 insert…select,這樣不僅快,而且不會要求鎖定
2. 一個鎖定記錄集的事務,其操作結果集應盡量簡短,以免一次佔用太多資源,與其他交易處理的記錄衝突。
3.更新或者刪除表格式資料,sql語句的where條件都是主鍵或都是索引,避免兩種情況交叉,造成死結。對於where子句較複雜的情況,將其單獨通過sql得到後,再在更新語句中使用。
4. sql語句的巢狀表格格不要太多,能拆分就拆分,避免佔有資源同時等待資源,導致與其他事務衝突。
5. 對定點運行指令碼的情況,避免在同一時間點運行多個對同一表進行讀寫的指令碼,特別注意加鎖且操作資料量比較大的語句。
6.應用程式中增加對死結的判斷,如果事務意外結束,重新運行該事務,減少對功能的影響。

查看死結記錄

show InnoDB STATUS \G語句在mysql用戶端中查看最近一次的死結記錄。

在遇到問題時先執行show processlist找到死結線程號.然後Kill processNo 當然主要解決還是需要去看一下具體的操作.可能產生死結Show innodb status檢查引擎狀態 ,可以看到哪些語句產生死結

Mysql鎖和死結分析

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.