性能優(yōu)化技巧:預(yù)關(guān)聯(lián)

一、 問題背景與適用場(chǎng)景

SQL中JOIN的性能是個(gè)老大難問題,特別是關(guān)聯(lián)表較多時(shí),計(jì)算性能會(huì)急劇下降。

SQL實(shí)現(xiàn)JOIN一般是采用HASH分堆的辦法,即先計(jì)算關(guān)聯(lián)鍵的HASH值,再將相同HASH值的記錄放到一起再做遍歷對(duì)比。每一個(gè)JOIN都要做一輪這樣的運(yùn)算。

如果數(shù)據(jù)量相對(duì)于內(nèi)存并不是很大,可以事先全部加載到內(nèi)存中,那么可以利用內(nèi)存指針的機(jī)制,事先把關(guān)聯(lián)關(guān)系建立好。這樣做運(yùn)算時(shí)就不必再做HASH與對(duì)比運(yùn)算了。具體來說,就是在數(shù)據(jù)加載時(shí)一次性把HASH和對(duì)比運(yùn)算做完,用指針方式保存關(guān)聯(lián)結(jié)果,然后每次運(yùn)算可以直接引用到關(guān)聯(lián)記錄,從而提高運(yùn)算的性能。

不幸的是,SQL沒有指針數(shù)據(jù)類型,無法實(shí)現(xiàn)這個(gè)優(yōu)化邏輯,即使數(shù)據(jù)量可以在內(nèi)存中裝下,也很難利用預(yù)關(guān)聯(lián)技巧提速,基于SQL的內(nèi)存數(shù)據(jù)庫也大都有這個(gè)缺點(diǎn)。而SPL有指針數(shù)據(jù)類型,就可以實(shí)現(xiàn)這種機(jī)制。

我們下面來測(cè)試一下SQL實(shí)現(xiàn)單表計(jì)算和多表關(guān)聯(lián)計(jì)算的差距,再用SPL利用預(yù)關(guān)聯(lián)技巧同樣做一遍,看一下兩者的差距對(duì)比。

二、 測(cè)試環(huán)境

采用TPCH標(biāo)準(zhǔn)生成的8張數(shù)據(jù)表,共50G數(shù)據(jù)(要小到能放進(jìn)內(nèi)存)。TPCH數(shù)據(jù)表的結(jié)構(gòu)網(wǎng)上有很多介紹,這里就不再贅述了。

測(cè)試機(jī)有兩個(gè)Intel2670 CPU,主頻2.6G,共16核,內(nèi)存128G,SSD固態(tài)硬盤。

由于 lineitem 表數(shù)據(jù)量太大,這臺(tái)服務(wù)器內(nèi)存不足以將它裝入,所以創(chuàng)建了一張表結(jié)構(gòu)與它一樣的表 orderdetail, 將數(shù)據(jù)量減少到內(nèi)存能裝下,下面就用這張表來做測(cè)試。

為方便看出差距,下面測(cè)試都用單線程計(jì)算,多核并不起作用。

三、 SQL測(cè)試

這里用 Oracle 數(shù)據(jù)庫作為 SQL 測(cè)試的代表,從orderdetail表里查詢每年零件訂單的總收入。

1. 兩表關(guān)聯(lián)

查詢的SQL語句如下:

select

l_year,

sum(volume) as revenue

from

(

select

extract(year from l_shipdate) as l_year,

(l_extendedprice * (1 - l_discount) ) as volume

from

orderdetail,

part

where

p_partkey = l_partkey

and length(p_type)>2

) shipping

group by

l_year

order by

l_year;

2. 六表關(guān)聯(lián)

查詢的SQL語句如下:

select

l_year,

sum(volume) as revenue

from

(

select

extract(year from l_shipdate) as l_year,

(l_extendedprice * (1 - l_discount) ) as volume

from

supplier,

orderdetail,

orders,

customer,

part,

nation n1,

nation n2

where

s_suppkey = l_suppkey

and p_partkey = l_partkey

and o_orderkey = l_orderkey

and c_custkey = o_custkey

and s_nationkey = n1.n_nationkey

and c_nationkey = n2.n_nationkey

and length(p_type) > 2

and n1.n_name is not null

and n2.n_name is not null

and s_suppkey > 0

) shipping

group by

l_year

order by

l_year;

3. 測(cè)試結(jié)果

兩個(gè)查詢語句都用了嵌套寫法,Oracle自動(dòng)優(yōu)化后的計(jì)算性能比無嵌套時(shí)還要好一些(無嵌套時(shí)group by和select有可能會(huì)有重復(fù)計(jì)算)。

這兩個(gè)測(cè)試數(shù)據(jù)是多次運(yùn)行后的結(jié)果,在測(cè)試中發(fā)現(xiàn),Oracle 在第一次運(yùn)行某查詢時(shí),往往比第 2、3... 次要慢很多,說明在內(nèi)存大于數(shù)據(jù)量時(shí),數(shù)據(jù)庫可以把全部數(shù)據(jù)都緩存進(jìn)內(nèi)存(Oracle的緩存很強(qiáng)),所以我們?nèi)《啻芜\(yùn)行中最快那一次的時(shí)間,這樣就幾乎沒有硬盤讀取時(shí)間,僅是運(yùn)算時(shí)間。

同時(shí),在上面兩組測(cè)試中,過濾條件始終都為真,也就是沒有對(duì)數(shù)據(jù)產(chǎn)生實(shí)質(zhì)過濾,兩個(gè)查詢都涉及orderdetail表的全部記錄,計(jì)算規(guī)模是相當(dāng)?shù)摹?/p>

從測(cè)試結(jié)果可以看出,六表關(guān)聯(lián)比兩表關(guān)聯(lián)慢了167/26=6.4倍!性能下降非常多。排除掉硬盤時(shí)間后,這里增加的時(shí)間主要就是表間關(guān)聯(lián)以及針對(duì)關(guān)聯(lián)表字段的判斷,而這些判斷非常簡單,所以大部分時(shí)間消耗在表間關(guān)聯(lián)上。

這個(gè)測(cè)試表明,SQL的JOIN性能確實(shí)很差。

四、 SPL預(yù)關(guān)聯(lián)測(cè)試

1. 預(yù)關(guān)聯(lián)

實(shí)現(xiàn)預(yù)關(guān)聯(lián)的SPL腳本如下:

腳本中前7行分別將7個(gè)組表讀入內(nèi)存,生成內(nèi)表,并設(shè)成全局變量。后5行完成表間連接。在SPL服務(wù)器啟動(dòng)時(shí),就先運(yùn)行此腳本,完成環(huán)境準(zhǔn)備。

我們來看看預(yù)關(guān)聯(lián)后,內(nèi)存中表對(duì)象的數(shù)據(jù)結(jié)構(gòu),以orderdetail為例:

圖中只列了orderdetail的第一條記錄的預(yù)關(guān)聯(lián)情況,其它記錄與此類似。限于版面寬度,各表只列出了部分字段。

2. 兩表關(guān)聯(lián)

編寫SPL腳本如下:

3. 六表關(guān)聯(lián)

編寫SPL腳本如下:

預(yù)關(guān)聯(lián)后,SPL代碼也非常簡單,關(guān)聯(lián)表的字段直接可以作為本表字段的子屬性訪問,很易于理解。

4. 運(yùn)行結(jié)果

六表關(guān)聯(lián)僅僅比兩表關(guān)聯(lián)慢2倍,基本上就是增加的計(jì)算量(引用這些關(guān)聯(lián)表字段)的時(shí)間,而因?yàn)橛辛祟A(yù)關(guān)聯(lián),關(guān)聯(lián)運(yùn)算本身不再消耗時(shí)間。

五、 結(jié)論

測(cè)試結(jié)果匯總:

六表關(guān)聯(lián)比兩表關(guān)聯(lián),SQL慢了6.4倍,說明SQL處理JOIN消耗CPU很大,性能降低明顯。而采用預(yù)關(guān)聯(lián)機(jī)制后的SPL只慢2倍,多JOIN幾個(gè)表不再出現(xiàn)明顯的性能下降。

在進(jìn)行關(guān)聯(lián)表較多的查詢時(shí),如果內(nèi)存大到足以將數(shù)據(jù)全部讀入內(nèi)存(內(nèi)存數(shù)據(jù)庫的應(yīng)用場(chǎng)景),使用預(yù)關(guān)聯(lián)技術(shù)將極大地提升計(jì)算性能!而關(guān)系數(shù)據(jù)庫(包括內(nèi)存數(shù)據(jù)庫)用SQL語言則無法實(shí)現(xiàn)這一優(yōu)化技術(shù)。

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

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

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