您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關InnoDB為什么update要盡量使用索引,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
問題:innodb行級鎖是通過鎖索引記錄實現的,如果update語句的where列沒建索引,即使只update一條記錄也會鎖住整張表嗎?
答案是肯定的。 我從當前本地數據庫中找出一張建立自增主鍵的表來演示。打開兩個終端窗口,用于驗證當a端執行update語句時b端是否會被鎖住。首先表的結構如下圖所示。
測試表stu_score中,id是主鍵索引,其它的列都是沒有建立索引的。現在要測試一下當執行update語句時,如果where沒有使用索引,那么是整張表都被鎖住呢,還是只會鎖住滿足條件的行呢?注意記得不要忘記開啟一個事務。
從上面的截圖中可以看出,當在A端執行where name=“wujiuye”的update語句時,雖然滿足name=“wujiuye”的記錄只有一條,但是innodb卻將整張表都鎖住了,在A端未將事務提交之前B端執行更新其它行的update語句被阻塞了。
接著來看一個使用索引的update示例
如上面截圖所示,在a端由于update語句只對id=1008的這條記錄做修改,id是主鍵,所以innodb只將id=1008的這行記錄加鎖了,所以在b端同樣只對id=1007的行做修改,所以也只會鎖住id=1007這行記錄。
你也可以驗證一下是否加了行鎖,在a、b端不同事務間對同一行記錄執行 update語句。
很明顯,a端先執行了update where id=1008,所以先獲取了id=1008這行記錄的鎖,然后再到b端執行update where id=1008的時候由于鎖已經被其它事務占用了,只能進入等待狀態。當a端提交事務時b端才會獲得鎖繼續執行,或者b端等待超時了(事務默認鎖超時50s)直接執行失敗,事務進行回滾。
如果你在b端執行where name=“wujiuye”的update語句就會進入阻塞了,因為它需要獲得表鎖,會將整個表鎖住,不信可以看下面的實驗結果。
使用行鎖會出現死鎖情況,來看個例子。
在a端先對id=1008這行記錄做update操作,獲得了id=1008的行鎖,(在需要的時候才會加鎖,但是只有事務提交的時候才會釋放鎖,這是二階段鎖的概念。)然后到b端對id=1007這行記錄做update操作,獲得了id=1007這行記錄的行鎖,這時候a事務持有id=1008的行鎖,b事務持有id=1007的行鎖,也都沒有什么問題,但是當a端繼續執行對b端已經加鎖的記錄執行寫操作時,就會進行阻塞狀態,而如果此時b端也想對a端加鎖的記錄執行寫操作,那么就會出現死鎖狀態了。
不過經過上面的實驗驗證,innodb已經默認幫我們排除死鎖情況了,所以出現當我在b端執行最后一句update的時候就立馬報錯了,提示:deadlock found when trying to get lock;嘗試獲取鎖時發現死鎖。
兩階段鎖協議:在 InnoDB 事務中,行鎖是在需要的時候才加上的,但并不是不需要了就立刻釋放,而是要等到事務結束時才釋放。
了解這個對我們有什么幫助?在并發情況下,對于那種多用戶共享操作的記錄是不是加鎖的時間越少越好?比如,購買一件商品,同一件商品是不是可以有多個用戶同時購買,這樣就是多個事務中訪問了同一商品表的同一行記錄,而購買付款是不是每個事務中只對當前用戶對應的記錄做修改,所以怎么優化呢?記住,只有在需要的時候才會加鎖,所以對商品記錄加行鎖是在減庫存的時候進行加鎖的,為了加鎖時間少,是不是可以先執行用戶的扣款操作,添加訂單記錄操作,最后再執行減庫存操作,然后提交事務,在準備提交事務時再執行減庫存操作,這樣就是減少加鎖時間,也能提交并發效率。
如果上面的例子看不懂沒關系,我在網上找了一個例子。 假設你負責實現一個電影票在線交易業務,顧客 A 要在影院 B 購買電影票。我們簡化一點,這個業務需要涉及到以下操作:
(1)從顧客 A 賬戶余額中扣除電影票價;
(2)給影院 B 的賬戶余額增加這張電影票價;
(3)記錄一條交易日志。
也就是說,要完成這個交易,我們需要 update 兩條記錄,并 insert 一條記錄。當然,為了保證交易的原子性,我們要把這三個操作放在一個事務中。
那么,你會怎樣安排這三個語句在事務中的順序呢?試想如果同時有另外一個顧客 C 要在影院 B 買票,那么這兩個事務沖突的部分就是語句 2 了。因為它們要更新同一個影院賬戶的余額,需要修改同一行數據。
根據兩階段鎖協議,不論你怎樣安排語句順序,所有的操作需要的行鎖都是在事務提交的時候才釋放的。所以,如果你把語句 2 安排在最后,比如按照 3、1、2 這樣的順序,那么影院賬戶余額這一行的鎖時間就最少。這就最大程度地減少了事務之間的鎖等待,提升了并發度。
關于InnoDB為什么update要盡量使用索引就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。