mysql innodb 并发 插入 慢_Innodb 锁机制——一次插入慢查询的排查
慢查詢?nèi)罩局?#xff0c;發(fā)下有一條插入語句慢查詢出現(xiàn)的概率比較高,一個簡單插入需要消耗4-10s,很不尋常。附上插入語句,省略了一些字段
INSERT INTO `fc_pay_out_trade_log` (`out_trade_no`,`dateline`) VALUES ('191120093724940457',1574185044) [ RunTime:4.176669s ]
fc_pay_out_trade_log 表除了主鍵,out_trade_no字段為普通索引,沒有其他索引。
mysql5.7版本,innodb引擎,默認(rèn)RR級別。
業(yè)務(wù)流程:
1.生成訂單流水id(out_trade_no),寫入訂單流水日志表fc_pay_out_trade_log,就是發(fā)送阻塞的語句
2.組合參數(shù),調(diào)用微信統(tǒng)一下單接口->微信操作支付然后回調(diào)回調(diào)接口
3.回調(diào)接口全部放到一個事務(wù)中處理,有個操作是更新訂單流水日志表fc_pay_out_trade_log對應(yīng)的訂單流水id的支付狀態(tài)
UPDATE `fc_pay_out_trade_log` SET `pay_status`=1,`pay_time`=1574221674 WHERE `out_trade_no` = '191120194747307594' [ RunTime:0.000716s ]
訂單流水out_trade_no生成規(guī)則
$out_trade_no = date(‘YmdHis’).rand(1000,9999);
對innodb鎖機制比較了解的人應(yīng)該發(fā)現(xiàn)了問題所在,這是因為update操作把innodb的間隙鎖把fc_pay_out_trade_log表的部分區(qū)域鎖住了,導(dǎo)致插入操作阻塞,必須等update操作的那個事務(wù)提交后才會釋放這個間隙鎖。
分析過程
1.前一個支付操作發(fā)生,支付成功后回調(diào)接口,執(zhí)行上面的update語句,更新的條件是WHERE out_trade_no = ‘191120194747307594’,為了保證不出現(xiàn)幻讀現(xiàn)象,innodb會使用next-key鎖,就是鎖住這行和間隙。
2.后一個支付發(fā)生,創(chuàng)建一個訂單流水,插入到fc_pay_out_trade_log表,發(fā)現(xiàn)插入的區(qū)域已經(jīng)被鎖住,阻塞等待
3.前一個支付處理完其他事情,提交事務(wù),釋放fc_pay_out_trade_log表的next-key鎖
4.后一個支付流水插入成功
下面這條語句會鎖定哪些區(qū)域?鎖多久才會釋放?
UPDATE `fc_pay_out_trade_log` SET `pay_status`=1,`pay_time`=1574221674 WHERE `out_trade_no` = '191120194747307594' [ RunTime:0.000716s ]
innodb鎖類型
S-共享鎖:又叫讀鎖,其他事務(wù)可以繼續(xù)加共享鎖,但是不能繼續(xù)加排他鎖。
X-排他鎖: 又叫寫鎖,一旦加了寫鎖之后,其他事務(wù)就不能加鎖
IS意向共享鎖:表達(dá)一個事務(wù)想要獲取一張表中某幾行的共享鎖。
IX意向排他鎖:表達(dá)一個事務(wù)想要獲取一張表中某幾行的共享鎖。
InnoDB鎖算法
記錄鎖
記錄鎖是鎖住記錄的,這里要說明的是這里鎖住的是索引記錄,而不是我們真正的數(shù)據(jù)記錄。
如果鎖的是非主鍵索引,會在自己的索引上面加鎖之后然后再去主鍵上面加鎖鎖住.
如果表上沒有索引(包括沒有主鍵),則會使用隱藏的主鍵索引進行加鎖。
如果要鎖的列沒有索引,則會進行全表記錄加鎖。
例如:select * from user where id= 1 for update; 會給user表加上IX,在主鍵索引1加上X鎖。
間隙鎖
鎖間隙的意思就是鎖定某一個范圍,間隙鎖又叫g(shù)ap鎖,其不會阻塞其他的gap鎖,但是會阻塞插入間隙鎖,這也是用來防止幻讀的關(guān)鍵。
我們來分析一下fc_pay_out_trade_log,out_trade_no字段是一個普通索引,并且新增的數(shù)據(jù)都是有順序的,所以WHERE out_trade_no = ‘191120194747307594’ 鎖住的間隙會包括[191120194747307594,~),而新插入的值一定會在這個間隙區(qū)域中,所以會產(chǎn)出阻塞。
next-key鎖
這個鎖本質(zhì)是記錄鎖加上gap鎖。在RR隔離級別下(InnoDB默認(rèn)),Innodb對于行的掃描鎖定都是使用此算法,但是如果查詢掃描中有唯一索引會退化成只使用記錄鎖。
解決辦法:修改fc_pay_out_trade_log表的out_trade_no字段設(shè)置為唯一索引即可
本作品采用《CC 協(xié)議》,轉(zhuǎn)載必須注明作者和本文鏈接
用過哪些工具?為啥用這個工具(速度快,支持高并發(fā)...)?底層如何實現(xiàn)的?
與50位技術(shù)專家面對面20年技術(shù)見證,附贈技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的mysql innodb 并发 插入 慢_Innodb 锁机制——一次插入慢查询的排查的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何正确使用烤箱,避免食物烤糊?
- 下一篇: mysql实现vpd_基于JDBC实现V