一次Mysql?update?sql不當(dāng)引起的生產(chǎn)故障記錄
故障表現(xiàn)
一方面 :在阿里云控制臺云數(shù)據(jù)庫PolarDB對應(yīng)的集群管理頁面上,在診斷與優(yōu)化模塊里面的一鍵診斷會話管理中,發(fā)現(xiàn)某條update sql 執(zhí)行時(shí)間非常久且非常頻繁;
另一方面:業(yè)務(wù)監(jiān)控系統(tǒng)中開始不斷有業(yè)務(wù)執(zhí)行時(shí)間發(fā)出告警信息提示,且告警的業(yè)務(wù)數(shù)據(jù)不斷上升,部分操作影響客戶使用。
業(yè)務(wù)背景
由于業(yè)務(wù)操作涉及到的業(yè)務(wù)流比較復(fù)雜,對純技術(shù)的分享來看,不是重點(diǎn)討論的話,為了更有利于理解問題發(fā)生的原因,使用類比的方式,把復(fù)雜的業(yè)務(wù)類比成如下描述: 有數(shù)據(jù)庫3張表,第一張表t_grandfather (爺表),第二張表為t_father(父表),第三張表t_grandson(子孫表),DDL如下:
CREATE TABLE `t_grandfather ` ( `id` int(11) NOT NULL AUTO_INCREMENT, `count` int(11) NOT NULL DEFAULT 0 COMMENT '子孫后代數(shù)量', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='老爺表'; CREATE TABLE `t_father ` ( `id` int(11) NOT NULL AUTO_INCREMENT, `grandfather_id` int(11) NOT NULL COMMENT '老爺表id', PRIMARY KEY (`id`), KEY `idx_grandfather_id` (`grandfather_id`), ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='老爸表'; CREATE TABLE `t_grandson` ( `id` int(11) NOT NULL AUTO_INCREMENT, `grandfather_id` int(11) NOT NULL COMMENT '老爺表id', PRIMARY KEY (`id`), KEY `idx_grandfather_id` (`grandfather_id`), ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='孫子表';
三張表之間的業(yè)務(wù)邏輯關(guān)系為,先生成老爺表,然后這個(gè)老爺取很多老婆(業(yè)務(wù)),會不斷的生娃,生一個(gè)娃就會生成一張老爸表,同時(shí)會更新老爺表的count=count+1,表示新增一個(gè)后代了,老爺?shù)睦掀牛I(yè)務(wù))在不斷的生娃的時(shí)候,之前的生的娃也會有老婆,他們的老婆也會生娃,對老爺來說,就是它有了孫子(產(chǎn)生新的業(yè)務(wù)數(shù)據(jù)),那有了孫子之后也需要更新老爺表的count=count+1,表示新增一個(gè)后代了,以此類推,子子孫孫無窮盡也(業(yè)務(wù)數(shù)據(jù)不斷生成) 如下圖所示:

祖?zhèn)鞔a的邏輯為,只要是t_father表和t_grandson有新增,就去更新t_grandfather。這個(gè)邏輯設(shè)計(jì)上問題不大,不過考慮到孫子表數(shù)據(jù)量很猛的時(shí)候,這里就會出現(xiàn)一個(gè)非常嚴(yán)重的性能問題。以下是業(yè)務(wù)摘取的一部分偽代碼
/**
* 處理 father 的業(yè)務(wù)
*/
public void doFatherBusiness (){
//do fatherBusiness baba .... 此處省
// 插入 t_father 表
if (fatherMapper.inster(father)){
//update t_grandfather set count=count+1 where id= #{grandfatherId}
grandfatherMapper.updateCount(father.getGrandfatherId ()) ;
}
}
/**
* 處理 grandson 的業(yè)務(wù)
*/
public void doGrandsonBusiness (){
//do grandson baba .... 此處省略
// 插入 t_grandson 表
if(grandsonMapper.inster(grandson)){
//update t_grandfather set count=count+1 where id= #{grandfatherId}
grandfatherMapper.updateCount(grandson.getGrandfatherId());
}
} 當(dāng)多個(gè)業(yè)務(wù)(線程)分別調(diào)用上面的方法時(shí),都會對t_grandfather表的更新操作造成巨大的壓力,特別是更新同一個(gè)id的情況下,mysql server內(nèi)部對鎖的競爭非常激烈。最后表現(xiàn)出來就如前文背景描述的一致。
解決方案
1. 臨時(shí)處理方案:
一方面,在阿里云控制臺,對sql進(jìn)行限流,在正常阻塞的會話,強(qiáng)制kill掉,讓數(shù)據(jù)的線程不阻塞著,釋放資源,另外一方面,在把接收請求的服務(wù)減少節(jié)點(diǎn)數(shù),目的是減少業(yè)務(wù)數(shù)據(jù)量進(jìn)入;
2. 長久方案
一方面更改掉上面的業(yè)務(wù)邏輯,插入t_grandson表和t_father表時(shí),不在去更新t_grandfather表的count字段;另一方面,需要用到count統(tǒng)計(jì)需求時(shí),全部切換成別的方式;
總結(jié)
到此這篇關(guān)于一次Mysql update sql不當(dāng)引起的生產(chǎn)故障的文章就介紹到這了,更多相關(guān)Mysql update sql生產(chǎn)故障內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
讓MySQL中某個(gè)表的操作不生成binlog日志的問題解決
文章介紹了四種方法讓MySQL中某個(gè)表的操作不生成binlog日志:會話級臨時(shí)關(guān)閉binlog、通過復(fù)制過濾規(guī)則、調(diào)整binlog格式和全局禁用binlog,每種方法都有其適用場景和局限性,建議優(yōu)先使用會話級臨時(shí)關(guān)閉方法,并根據(jù)具體需求選擇合適的方案,感興趣的朋友跟隨小編一起看看吧2025-03-03
Mysql查詢很慢卡在sending data的原因及解決思路講解
今天小編就為大家分享一篇關(guān)于Mysql查詢很慢卡在sending data的原因及解決思路講解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-04-04
生產(chǎn)環(huán)境的MySQL事務(wù)隔離級別方式
本文探討了MySQL數(shù)據(jù)庫在RR(可重復(fù)讀)和RC(讀已提交)隔離級別下的鎖機(jī)制,在RR級別下,UPDATE語句會鎖定所有符合條件的行,包括不符合條件的行,以防止幻讀,而在RC級別下,UPDATE語句僅鎖定符合條件的行,通過半一致性讀優(yōu)化,可以進(jìn)一步提高并發(fā)度2025-02-02
數(shù)據(jù)庫索引的知識點(diǎn)整理小結(jié),你所需要了解的都在這兒了
這篇文章主要介紹了數(shù)據(jù)庫索引的知識點(diǎn)整理小結(jié),你所需要了解的都在這兒了,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07
MySQL的查詢緩存機(jī)制基本學(xué)習(xí)教程
這篇文章主要介紹了MySQL的查詢緩存機(jī)制基本學(xué)習(xí)教程,默認(rèn)針對InnoDB存儲引擎下來將,需要的朋友可以參考下2015-11-11
MySQL數(shù)據(jù)庫的實(shí)時(shí)備份知識點(diǎn)詳解
本篇文章給大家分享了關(guān)于MySQL數(shù)據(jù)庫的實(shí)時(shí)備份知識點(diǎn)內(nèi)容,有需要的朋友們可以參考下。2018-08-08

