一、 問題背景與適用場景
在《性能優化技巧:小事實表與大維表關聯》中,我們嘗試了小事實表與大維表關聯時的性能優化方法,該方法利用了小事實表可以裝入內存的特點,將關聯鍵彙集排序後到大維表中查找,避免了遍歷大維表的動作。如果事實表與維表都大到不能裝載到內存時,這個辦法就不再有效了,那麼,還有什麼辦法提高性能呢?
SQL的方案是對兩個表做HASH分堆,拆小到內存可以放下的地步,分別寫入外存,然後再分別讀入進行內存關聯。如果運氣不好,拆出來的某個堆還是太大,就需要做二次HASH。同時,兩個表都需要做一遍HASH分堆動作,也就是需要把所有數據都緩存一遍。
如果維表是有序存放的,我們就可以將平均分段,由於有序存儲,所以可以計算出每一段值的邊界值,然後再用這個邊界值將事實表再分堆。這樣,維表本身由於有序存儲,可以直接按段讀取,而不需要再分堆;只有事實表被緩存出去,也就是隻有一個表被分堆緩存,所以這種辦法可以稱爲單邊方案。而且,由於維表可以被相對平均分段,不可能象HASH方法那樣出現運氣不好導致某堆太大的情況,一次分堆一定能解決問題,性能將得到保障。
SPL提供了這種關聯方法,下面我們實例測試一下,並且與使用HASH JOIN算法的Oracle對比。
二、 測試環境與任務
測試機有兩個Intel2670 CPU,主頻2.6G,共16核,內存64G,SSD固態硬盤。在此機上安裝虛擬機來測試,設置虛擬機爲16核、8G內存。
在虛擬機上創建維表account,共三個字段accountid、name、state,總記錄共10億行。創建事實表trade,總記錄共16億行,共四個字段tradedate、outid(轉出帳戶)、receiveid(接收帳戶)、amount(轉帳金額)。account表中的accountid是事實表中outid和receiveid的外鍵,都是一對多的關係。
在《性能優化技巧:小事實表與大維表關聯》中我們測試的是outid、receiveid兩個字段都要與account表中的accountid關聯,稱之爲雙維表。測試結果可見當事實表記錄數爲1500萬行時,Oracle運行時間已經接近5小時,而這次測試的事實表最少記錄數爲10億行,用Oracle運行的時間就會超過24小時了,所以測試只有outid關聯的情況,稱之爲單維表。測試任務爲查詢某段時期內各州轉出資金總額。
在SPL測試中,會用雙維表與單維表作對比測試。
爲縮短測試時間,全部採用4個並行。
三、 測試
1. Oracle測試
編寫查詢測試SQL如下:
select /*+ parallel(4) */
state,
sum(amount) as amount
from
account,
trade
where
outid = accountid
and tradedate >= date '2008-01-01' + interval '1500' day(4)
group by
state
order by
state;
其中/*+ parallel(4) */ 表示4個並行。
2. SPL測試
編寫SPL腳本如下:
A | |
1 | =now() |
2 | =elapse(date("2008-01-01"),1500) |
3 | =file(path+"account.ctx").create() |
4 | =file(path+"trade.ctx").create().cursor@m(outid,amount;tradedate>=A2;4) |
5 | =A4.joinx@u(outid,A3:accountid,state;4000000) |
6 | =A5.groups(state;sum(amount):amount) |
7 | =interval@s(A1,now()) |
joinx時加選項@u就適用於大事實表與大維表關聯,它的最後一個參數指明把遊標拆分爲多路時,每次從遊標中讀取的記錄數,在內存能裝下的情況下,此值越大性能越高。
3. 測試結果及分析
事實表不同數據量時的測試結果如下(單位:秒):
事實表過濾後記錄數 | 10億 | 12億 | 14億 | 15億 | 16億 |
Oracle | 730 | 802 | 860 | 894 | >10小時 |
SPL | 486 | 562 | 643 | 681 | 730 |
經測算,10億行數據正常情況會超過8G內存,優秀的Oracle可能採用了數據壓縮技術,致使能裝下15億行數據。但是在16億行數據時,內存就怎麼也放不下了,開始發生大量佔用swap區的現象,也造成運行速度奇慢,測試中等了11小時也沒查詢出來,只好終止了。而SPL這種單邊技術,不受數據量大小的限制,本來就是面向外存設計,而且一次分堆就能解決,時間基本上呈線性增加。
四、 SPL雙維表與單維表對比測試
1. 單維表
編寫單維表測試SPL腳本如下:
A | |
1 | =now() |
2 | =elapse(date("2008-01-01"),1500) |
3 | =file(path+"account.ctx").create() |
4 | =file(path+"trade.ctx").create().cursor@m(outid,receiveid,amount;tradedate>=A2;4) |
5 | =A4.joinx@u(outid,A3:accountid,state;4000000) |
6 | =A5.groups(state;sum(amount):amount) |
7 | =interval@s(A1,now()) |
2. 雙維表
編寫雙維表測試SPL腳本如下:
A | |
1 | =now() |
2 | =elapse(date("2008-01-01"),1500) |
3 | =file(path+"account.ctx").create() |
4 | =file(path+"trade.ctx").create().cursor@m(outid,receiveid,amount;tradedate>=A2;4) |
5 | =A4.joinx@u(outid,A3:accountid,state:out_state;receiveid,A3:accountid,state:receive_state;4000000) |
6 | =A5.groups(out_state;sum(amount):amount) |
7 | =interval@s(A1,now()) |
3. 測試結果及分析
事實表不同數據量時的測試結果如下(單位:秒):
事實表過濾後記錄數 | 10億 | 12億 | 14億 | 16億 |
單維表 | 500 | 614 | 664 | 782 |
雙維表 | 1146 | 1375 | 1501 | 1957 |
雙維表比單維表多了一倍的關聯計算量,運算時間也僅僅略多於一倍,也是呈線性增加的,不會發生完全不可控的局面。