Mysql索引合并

有一天在查詢生產(chǎn)異常日志的時候,突然發(fā)現(xiàn)了Mysql死鎖的日志,第一反應(yīng)則是:臥槽,我寫的代碼居然有死鎖,帶著疑問開始了長達(dá)半個小時的百度之旅,最終才知道原因是索引合并導(dǎo)致。

何為索引合并

1、顧名思義,索引合并,就是把多個索引到的數(shù)據(jù)合并成一個
2、索引合并的時候,會對索引進(jìn)行并集,交集操作,以便合成一個索引。
3、這些需要合并的索引只能是一個表的,不能對多表進(jìn)行索引合并。

舉個例子

在下面的sql中,字段name和age都分別建了索引,查詢時會分別通過name=lyy和age=18查找符合條件的數(shù)據(jù),然后進(jìn)行合并獲取到主鍵id,再回表查詢,然后對兩個條件查詢到的id進(jìn)行交集,這個交集合并的過程就叫索引合并。
select * from user where name = 'lyy' and age = 18


索引合并

為什么索引合并會導(dǎo)致死鎖

死鎖:我們先回顧下,什么是死鎖?
兩個或者兩個以上的進(jìn)程在執(zhí)行的過程中,因爭奪一些公共的資源,導(dǎo)致雙方都占有了對方需要獲取到才能繼續(xù)往下執(zhí)行的不同資源時,發(fā)生了互相一直等待的情況。這就叫死鎖。

因?yàn)樗饕喜l(fā)生死鎖的sql

update sop_task_statistics set task_num = task_num + #{dto.taskNum}, score = score + #{dto.score}
where slxt_account = #{dto.slxtAccount} and area_id = #{dto.areaId} and month_date = #{dto.monthDate}

因?yàn)閿?shù)據(jù)庫表分別對slxt_account、area_id、month_date字段建了索引,所以在執(zhí)行上面的sql時會對上面的三個字段索引進(jìn)行了鎖定操作,并且進(jìn)行了回表操作時也對主鍵索引進(jìn)行了鎖定,所以對索引的鎖定次數(shù)達(dá)到了6次。

為什么這個sql會導(dǎo)致死鎖?

我們用兩個事務(wù)來分析下該sql的執(zhí)行過程


死鎖發(fā)生過程

如何解決上面的死鎖

1、創(chuàng)建組合索引(slxt_account,area_id,month_date),這樣在執(zhí)行上面的sql語句時,通過組合索引直接定位到具體的主鍵索引id,更新操作變成了行鎖,并且鎖粒度細(xì)化到一行,這樣就不會導(dǎo)致兩個事務(wù)都鎖定了對方需要獲取到才能繼續(xù)往下執(zhí)行的資源。
2、先查詢,查詢操作不會發(fā)生鎖操作,查詢到具體的主鍵id,然后通過id進(jìn)行更新操作,也就是更新sql改為下面這樣
update sop_task_statistics set task_num = task_num + #{dto.taskNum}, score = score + #{dto.score} where id = #{id}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容