圖文詳解Mysql使用left?join寫查詢語句執(zhí)行很慢問題的解決
(一)前言
這幾天供應(yīng)商在測試環(huán)境上使用MYSQL數(shù)據(jù)庫做開發(fā)時遇到一個SQL性能問題,即在他開發(fā)環(huán)境本地跑SQL速度很快就一兩秒時間,但是同樣的SQL放在測試環(huán)境上死活跑了很久一直出不了結(jié)果。最后求助到我這邊,以下正文是我解決這次問題的一個過程淺談,供大家參考。
(二)正文
本文使用NAVICAT試用版作為基礎(chǔ)工具來說明,需要永久激活的可以在網(wǎng)上找到相關(guān)介紹走正式途徑。
其次附上一篇文章,解釋說明如果在NAVICAT中運行一條長時間的SQL想關(guān)閉終止它,圖形化點擊失敗時候所應(yīng)該采取的方式,文章鏈接如下:
1. 表結(jié)構(gòu)/索引展示
以下將大致描述下本次遇到性能問題涉及的兩張表(rep_consultant_first和rep_newcomer_consultant)的表結(jié)構(gòu)和索引。
(1)表結(jié)構(gòu)
a. rep_consultant_first
b. rep_newcomer_consultant
(2)各表索引情況
a. rep_consultant_first
b. rep_newcomer_consultant
2. 存在性能問題的SQL語句
這條SQL語句的意圖在于找出rep_newcomer_consultant表中缺失的存在于rep_consultant_first表中的數(shù)據(jù),即可求這兩張表的差集(rep_consultant_first - rep_newcomer_consultant),簡單說就是下圖里的紅色填充區(qū)域。
select consultantNumber, customerId,userName, telephoneNumber, sponsorConsultantNumber, signUpDate from rep_consultant_first rcf left join rep_newcomer_consultant rnco on rnco.rncoConsultantNumber=rcf.consultantNumber where rnco.rncoConsultantNumber is null;
直接運行后我們發(fā)現(xiàn)這條語句運行了好幾十分鐘依舊沒有結(jié)果,假如只是稍微慢一點那可能勉強說得過去,但是目前這種情況實在是到無法接受的情況了?。?!
3. 解決思路
(1)執(zhí)行計劃思路調(diào)優(yōu)
一般SQL慢了,第一個想的一定是查一下執(zhí)行計劃是不是哪個環(huán)節(jié)沒有走索引,走了全表掃描,讓我們選中SQL部分,點擊“解釋已選擇的”來看下這條SQL的執(zhí)行計劃詳情:
從執(zhí)行計劃中我們看到別名為rcf(即rep_consultant_first表)的type方式走了ALL,即全表掃描,那自然而然我們會先想從這里去優(yōu)化。
回到rep_consultant_first表的索引位置,我們看到在select后篩出來的字段里只有consultant number和sponsorConsultantNumber字段上有索引而其他并沒有,所以不可避免走了全表掃描
那我們先嘗試下給未加索引的字段加上一組索引,大致流程如下:
a. 找到所要加索引字段所在的表(rep_consultant_first),右鍵點擊后選擇"設(shè)計表"
b. 找到索引選項卡,添加索引TestIndex,最后點擊保存。
讓我們重新回到一開始的SQL,看一下加完索引后是否執(zhí)行計劃有優(yōu)化:
可以看出,執(zhí)行計劃的TYPE從ALL變成了INDEX且EXTRA列明確說明了Using index了,那說明執(zhí)行計劃確實改變了,沒有掃全表,不過遺憾的是。。。SQL依舊跑不出來。。。
(2)字符集匹配調(diào)優(yōu)
此時真的黔驢技窮了么??還真沒有 !足球籃球世界里我們經(jīng)常看到最后時刻逆襲的致命一擊取得勝利,在SQL優(yōu)化里我們同樣有這樣的機會! 仔細回想了下,似乎在MYSQL相關(guān)手冊資料中的優(yōu)化TIPS里除了添加相關(guān)字段索引之外,那left join中關(guān)聯(lián)兩表的字段,字符集是否需要統(tǒng)一???
有了這個思路,我們立馬著手再看下這條問題SQL語句,我們重點關(guān)注rep_consultant_first表上的consultantNumber字段以及rep_newcomer_consultant表上的rncoConsultantNumber字段:
對比之下,立馬看出了區(qū)別!在rep_consultant_first上字段consultantNumber的字符集為utf8mb4,而rep_newcomer_consultant上字段rncoConsultantNumber的字符集為gbk。在官方相關(guān)文檔中提到過關(guān)聯(lián)字段除了需要有索引外,擁有相同的字符集以及數(shù)據(jù)類型相當(dāng)重用,這會極大影響查詢速度!
接下來我們來具體操作下,可以將rep_newcomer_consultant上字段rncoConsultantNumber的字符集改從gbk改為utf8mb4,排序方式也改為和rep_consultant_first表一樣的utf8mb4_0900_ai_ci試一試,點擊保存按鈕:
保存成功后,我們立馬再運行下慢SQL:
一下子只有0.885秒了??!速度飆升到無法言喻的速度!至此我們基本算優(yōu)化成功了。
(三)總結(jié)
經(jīng)過這個案例后,我搜羅總結(jié)了下本例涉及到一些優(yōu)化注意點:
1. 關(guān)于執(zhí)行計劃中TYPE的性能比較
2. 關(guān)于left join優(yōu)化
1、left join選擇小表作為驅(qū)動表(這部分基本是大家的共識)
2、如果左表比較大,并且業(yè)務(wù)要求驅(qū)動表必須是左表,那么我們可以通過where條件語句,使得左表被過濾的小一些,主要原理和第一條類似
3、關(guān)聯(lián)字段給索引,因為在mysql的嵌套循環(huán)算法中,是通過關(guān)聯(lián)字段進行關(guān)聯(lián),并查詢的,所以給關(guān)聯(lián)字段索引很必要
4、如果sql里面有排序,請給排序字段加上索引,不然會造成排序使用全表掃描
參考:https://www.oschina.net/question/930697_2190172
5、如果where條件中含有右表的非空條件(除開is null),則left join語句等同于join語句,可直接改寫成join語句。6、根據(jù)文檔,MySQL能更高效地在聲明具有相同類型和尺寸的列上使用索引。所以把表與表之間的關(guān)聯(lián)字段給上encoding和collation(決定字符比較的規(guī)則)全部改成統(tǒng)一的類型
7、右表的條件列一定要加上索引(主鍵、唯一索引、前綴索引等),最好能夠使type達到range及以上(ref,eq_ref,const,system)
3. 其他注意點
總結(jié)
到此這篇關(guān)于Mysql使用left join寫查詢語句執(zhí)行很慢問題解決的文章就介紹到這了,更多相關(guān)Mysql left join查詢語句執(zhí)行很慢內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Mysql賬號管理與引擎相關(guān)功能實現(xiàn)流程
Mysql中的每一種技術(shù)都使用不同的存儲機制、索引技巧、鎖定水平、并且最終提供廣泛的不同功能和能力。通過選擇不同的技術(shù),你能夠獲得額外的速度或者功能,從而改善應(yīng)用的整體功能。這些不同的技術(shù)以及配套的相關(guān)功能在MySQL中被稱作存儲引擎2022-10-10MySQL8.0登錄時出現(xiàn)Access?denied?for?user?‘root‘@‘localhost‘?
這篇文章主要給大家介紹了解決MySQL8.0登錄時出現(xiàn)Access?denied?for?user?‘root‘@‘localhost‘?(using?password:?YES)?拒絕訪問的問題,文中有詳細的解決方法,需要的朋友可以參考下2023-09-09