分享幾則MySQL問題處理案例楣嘁,聊聊我的思路。處理問題的思路和角度各有不同拐格,希望這篇文章可以拋磚引玉。
問題一刑赶、
問題描述:某功能模塊涉及保存和提交類操作慢捏浊,反映到數(shù)據(jù)庫環(huán)境為DML操作普遍偏慢。
處理過程:排查MySQL數(shù)據(jù)庫發(fā)現(xiàn)所有涉及批量插入的功能都有性能問題撞叨,數(shù)據(jù)庫選用的是微軟云的RDS金踪,對比生產(chǎn)環(huán)境和測試開發(fā)環(huán)境,生產(chǎn)環(huán)境的硬件配置比測試開發(fā)環(huán)境高很多牵敷,插入反而更慢胡岔。嘗試使用腳本驗(yàn)證兩個(gè)環(huán)境的插入速度:
同樣的網(wǎng)絡(luò)環(huán)境,插入3萬條數(shù)據(jù)枷餐,測試環(huán)境用時(shí)6s靶瘸,而生產(chǎn)環(huán)境用時(shí)9s;對比兩個(gè)環(huán)境數(shù)據(jù)庫參數(shù)的差異發(fā)現(xiàn)生產(chǎn)環(huán)境開啟了binlog,而測試環(huán)境未開啟:
經(jīng)與云廠商確認(rèn)后奕锌,生產(chǎn)環(huán)境有災(zāi)備和自動(dòng)備份的功能著觉,開啟此功能默認(rèn)需要打開binlog,而廠商為了確保數(shù)據(jù)的完整性惊暴,將sync_log的值設(shè)置為1饼丘,即每一個(gè)事務(wù)都需要刷新數(shù)據(jù)到磁盤,這樣就導(dǎo)致數(shù)據(jù)庫的dml操作性能下降很多辽话。
總結(jié):開啟binlog之后建議合理規(guī)劃以下兩個(gè)參數(shù)的值來提高數(shù)據(jù)庫性能:sync_binlog = 0 ##控制多少事務(wù)刷新一次binlog肄鸽,0代表由文件系統(tǒng)控制。
innodb_flush_log_at_trx_commit = 2 ##控制log buffer的羅盤機(jī)制油啤,默認(rèn)1s刷新一次典徘。以上的設(shè)置可以使用緩存機(jī)制,增加數(shù)據(jù)庫插入和修改的速度益咬,但是會(huì)帶來一定的風(fēng)險(xiǎn)逮诲,服務(wù)器意外宕機(jī)可能會(huì)丟失部分緩存中的數(shù)據(jù)。
問題二幽告、
問題描述:慢SQL導(dǎo)致數(shù)據(jù)庫CPU告警
解決過程:某功能模塊慢SQL導(dǎo)致系統(tǒng)卡死梅鹦,且SQL執(zhí)行頻率較高。到MySQL數(shù)據(jù)庫發(fā)現(xiàn)如下SQL嚴(yán)重阻塞:SQL文本結(jié)構(gòu)如下:
1
delete from 表A where a.字段1 in (select b.字段1 from 表B 冗锁, 表C where b.字段2=xx and b.字段2=c.字段2 and c.字段3=0)
此SQL在功能上循環(huán)調(diào)用執(zhí)行齐唆,效率極差。先從索引層面優(yōu)化冻河,表B/C都缺失索引箍邮,刪除的效率極低。增加如下索引:
create index idx_name ON 表B(字段2);
create index idx_name ON 表C(字段3);
通過添加索引當(dāng)然能有效的優(yōu)化SQL執(zhí)行效率叨叙。我們再來看一下SQL的邏輯锭弊,這么簡單的邏輯有必要搞個(gè)子查詢嗎?來嘗試修改一下SQL寫法摔敛,修改后如下:
delete 表Afrom 表A , 表B , 表C where b.字段2 = xx and b.字段2 = c.字段2 and a.字段1 = c.字段1 and c.字段3 = 0
修改后的SQL(0.5s以內(nèi))
總結(jié):通過掃描SQL代碼發(fā)現(xiàn)較多的SQL開發(fā)人員習(xí)慣使用exists和in的邏輯來過濾數(shù)據(jù)廷蓉,但是在MySQL中,exists的性能并不是最高的马昙,即使在字段存在索引的情況下桃犬,在結(jié)果集比較大情況下,
exists的檢索速度遠(yuǎn)不如inner join的hash連接行楞,而且過多的使用exists容易導(dǎo)致SQL的執(zhí)行計(jì)劃異常攒暇,而inner join邏輯相對更加直接,簡化子房。我推薦的優(yōu)先邏輯:join > exists > in形用。
問題三就轧、問題描述:再來看一個(gè)慢SQL優(yōu)化案例。
解決過程:數(shù)據(jù)庫整體負(fù)載壓力較大田度,分析慢日志優(yōu)化了部分性能較差的SQL后有明顯改善妒御,此處列舉出一個(gè)比較典型的優(yōu)化案例:某功能模塊更新文檔閱讀數(shù)的一個(gè)定時(shí)任務(wù),原SQL執(zhí)行時(shí)間穩(wěn)定在5秒左右镇饺。SQL文本結(jié)構(gòu)如下(將就著看):
查看它的執(zhí)行計(jì)劃:可以發(fā)現(xiàn)乎莉,此處的in條件中,MySQL選用了全表掃描的方法進(jìn)行匹配奸笤,字段的單列索引是有的惋啃, 與開發(fā)人員溝通后,in中的結(jié)果不會(huì)很大监右,我們可以將SQL進(jìn)行分離:
將in的條件單獨(dú)拿出來查詢边灭,然后將獲取到的結(jié)果拼接到后面的SQL中對比執(zhí)行計(jì)劃,此時(shí)SQL執(zhí)行速度可以達(dá)到毫秒級別
總結(jié):SQL的邏輯越簡單越好健盒,應(yīng)盡量的簡化SQL邏輯绒瘦,減少這種嵌套,SQL拼接的操作味榛,盡量把一個(gè)大的SQL剝離成小的SQL去運(yùn)行椭坚,不同數(shù)據(jù)庫對SQL的執(zhí)行計(jì)劃有出入予跌,越復(fù)雜的SQL帶過來的隱患就越大搏色,簡潔的SQL邏輯總是最高效最健壯的。