溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

SQL慢查詢(xún)優(yōu)化的方法是什么

發(fā)布時(shí)間:2022-01-06 14:30:12 來(lái)源:億速云 閱讀:180 作者:iii 欄目:開(kāi)發(fā)技術(shù)

本篇內(nèi)容主要講解“SQL慢查詢(xún)優(yōu)化的方法是什么”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“SQL慢查詢(xún)優(yōu)化的方法是什么”吧!

1.背景

頁(yè)面無(wú)法正確獲取數(shù)據(jù),經(jīng)排查原來(lái)是接口調(diào)用超時(shí),而最后發(fā)現(xiàn)是因?yàn)镾QL查詢(xún)長(zhǎng)達(dá)到20多秒而導(dǎo)致了問(wèn)題的發(fā)生。
這里,沒(méi)有高深的理論或技術(shù),只是備忘一下經(jīng)歷和解讀一些思想誤區(qū)。

2.復(fù)雜SQL語(yǔ)句的構(gòu)成

這里不過(guò)多對(duì)業(yè)務(wù)功能進(jìn)行描述,但為了突出問(wèn)題所在,會(huì)用類(lèi)比的語(yǔ)句來(lái)描述當(dāng)時(shí)的場(chǎng)景

復(fù)雜的SQL語(yǔ)句可以表達(dá)如下:

SELECT * FROM a_table AS a 
LEFT JOIN b_table AS b ON a.id=b.id 
WHERE a.id IN (
SELECT DISTINCT id FROM a_table 
WHERE user_id IN (100,102,103) GROUP BY user_id HAVING count(id) > 3
)

3.關(guān)聯(lián)查詢(xún)

從上面簡(jiǎn)化的SQL語(yǔ)句,可以看出,首先進(jìn)行的是關(guān)聯(lián)查詢(xún)。

4.子查詢(xún)

其次,是嵌套的子查詢(xún)。此子查詢(xún)是為了找出多個(gè)用戶(hù)共同擁有的組ID。所以語(yǔ)句中的“100,102,103”是根據(jù)場(chǎng)景來(lái)定的,并且需要和后面“count(id) > 3”的個(gè)數(shù)對(duì)應(yīng)。簡(jiǎn)單來(lái)說(shuō),就是找用戶(hù)交集的組ID。

5.耗時(shí)在哪?

假設(shè)現(xiàn)在a_table表的數(shù)據(jù)量為20W,而b_table的數(shù)據(jù)量為2000W。大家可以想一下,你覺(jué)得主要的耗時(shí)是在關(guān)聯(lián)查詢(xún)部分,還是在子查詢(xún)部分?
(思考空間。。。。)
(思考空間。。。。。。。)
(思考空間。。。。。。。。。。)

6.問(wèn)題定位

對(duì)于SQL底層的原理和高深的理論,我暫時(shí)掌握不夠深入。但我知道可以通過(guò)類(lèi)比和簡(jiǎn)單的測(cè)試來(lái)驗(yàn)證是哪一塊環(huán)節(jié)出了問(wèn)題。

7.初步斷定

首先,對(duì)于只有一個(gè)用戶(hù)ID時(shí),我會(huì)把上面的語(yǔ)句簡(jiǎn)化成:

ELECT * FROM a_table AS a 
LEFT JOIN b_table AS b ON a.id=b.id 
WHERE user_id IN (100)

所以,初步斷定應(yīng)該是嵌套的子查詢(xún)部分占用了大部分的時(shí)間。

9.再進(jìn)一步驗(yàn)證

既然定位到了是嵌套的子查詢(xún)語(yǔ)句的問(wèn)題,那又要分為兩塊待排查的區(qū)域:是子查詢(xún)本身耗時(shí)大,還是嵌套而導(dǎo)致慢查詢(xún)?
結(jié)果很容易發(fā)現(xiàn),當(dāng)我把子查詢(xún)單獨(dú)在DB中執(zhí)行時(shí),是非??斓?。所以排除。
剩下的不言而喻,20秒的慢查詢(xún)是嵌套引起的。

但因?yàn)樘幱谏暇€(xiàn)緊急的過(guò)程中,為了確保,我快速地驗(yàn)證了我的結(jié)論:

  • 1、將子查詢(xún)的ID單獨(dú)執(zhí)行,并把得到的結(jié)果序列手動(dòng)拼成一段ID,如:1,2,3,4, … , 999

  • 2、將上面得到的序列ID,手動(dòng)替換到原來(lái)的SQL語(yǔ)句

  • 3、執(zhí)行,發(fā)現(xiàn),很快!只用了約150 ms

Well Done!  準(zhǔn)備修復(fù)上線(xiàn)!

10.解決方案

線(xiàn)上的問(wèn)題,很多時(shí)間都是在定位問(wèn)題和分析原因,既然問(wèn)題找到了,原因也找到了,解決方案不言而喻。代碼簡(jiǎn)單處理即可。

11.另外一個(gè)需要注意的點(diǎn)

當(dāng)前,實(shí)際的SQL語(yǔ)句,會(huì)比這個(gè)更為復(fù)雜,但已足以表達(dá)問(wèn)題所在。但在前期,筆者也做了一些SQL的代碼。
因?yàn)?code>b_table比a_table大,所以一開(kāi)始b_table 左關(guān)聯(lián)a_table 時(shí),很慢,大概是1秒多,而且數(shù)據(jù)量是很少的;但若反過(guò)來(lái),a_table 左關(guān)聯(lián)b_table 時(shí),則很快,大概是100毫秒。

所以,又發(fā)現(xiàn)一個(gè)有趣的現(xiàn)象:

大表 左關(guān)聯(lián) 小表,很慢;小表 左關(guān)聯(lián) 大表,很快。
當(dāng)然,這些我們理論上都知道,但實(shí)際開(kāi)發(fā)會(huì)忘卻。又或者一開(kāi)始兩個(gè)表都為空時(shí),而又沒(méi)考慮到后期這兩個(gè)表增長(zhǎng)的速度時(shí),日后就會(huì)埋下坑了。

到此,相信大家對(duì)“SQL慢查詢(xún)優(yōu)化的方法是什么”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢(xún),關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

sql
AI