在《效能優化技巧:預關聯》中,我們測試了將資料表事先全部載入進記憶體並做好關聯後的查詢效能優化問題,但如果記憶體不夠大,不能將維表和事實表全部裝入,那怎麼辦呢?此時,可以將維表預先裝入記憶體,建好索引,實現維表部分的預關聯,省去一半hash計算。
我們下面再來測試一下這種場景,這次用資料量最大、記憶體裝不下的lineitem表做測試,在spl部分預關聯中,將其它7張表預先裝進記憶體,而lineitem在查詢時才實時讀入。
依然用 oracle 資料庫作為 sql 測試的代表,從lineitem表裡查詢每年零件訂單的總收入。
查詢的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
lineitem,
part
where
p_partkey = l_partkey
and length(p_type)>2
) shipping
group by
l_year
order by
l_year;
查詢的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,
lineitem,
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;
兩表關聯
六表關聯
執行時間(秒)
2352669
這兩個測試資料依然是多次執行後取最快的那次。
從測試結果可以看出,六表關聯比兩表關聯慢了2669/235=11.4倍!效能下降非常多。
實現預關聯的spl指令碼如下:
a
1>env(region, file(path+"region.ctx").create().memory().keys@i(r_regionkey))
2>env(nation, file(path+"nation.ctx").create().memory().keys@i(n_nationkey))
3>env(supplier, file(path+"supplier.ctx").create().memory().keys@i(s_suppkey))
4>env(customer, file(path+"customer.ctx").create().memory().keys@i(c_custkey))
5>env(part, file(path+"part.ctx").create().memory().keys@i(p_partkey))
6>env(orders,file(path+"orders.ctx").create().memory().keys@i(o_orderkey))
7>nation.switch(n_regionkey,region)
8>customer.switch(c_nationkey,nation)
9>supplier.switch(s_nationkey,nation)
10>orders.switch(o_custkey,customer)
指令碼中前6行分別將6個維表讀入記憶體,生成內錶,並建好索引,再設成全域性變數。後4行完成維表間連線。在spl伺服器啟動時,就先執行此指令碼,完成環境準備。
編寫spl指令碼如下:
a
1=file("/home/btx/lineitem.btx").cursor@tb(l_partkey,l_extendedprice,l_discount,l_shipdate)
2=a1.switch@i(l_partkey,part).select(len(l_partkey.p_type)>2)
3=a2.groups(year(l_shipdate):l_year; sum(l_extendedprice * (1 - l_discount)):revenue)
臨時裝載需要用游標,然後在游標上進行關聯,之後的寫法和全記憶體差不多。
編寫spl指令碼如下:
a
1=file("/home/btx/lineitem.btx").cursor@tb(l_orderkey,l_partkey,l_suppkey,l_extendedprice,l_discount,l_shipdate)
2=a1.switch@i(l_orderkey,orders;l_partkey,part;l_suppkey,supplier)
3=a2.select(len(l_partkey.p_type)>2 && l_orderkey.o_custkey.c_nationkey.n_name!=null && l_suppkey.s_nationkey.n_name != null && l_suppkey.s_suppkey>0 )
4=a3.groups(year(l_shipdate):l_year;
sum(l_extendedprice * (1 - l_discount)):revenue)
類似地,建立好游標及關聯後的寫法和全記憶體差不多,一樣非常簡潔易懂。
兩表關聯
六表關聯
執行時間(秒)
266472
六表關聯僅僅比兩表關聯慢1.8倍,增加的時間主要用於事實表lineitem中l_orderkey和l_suppkey欄位的關聯以及增加的過濾條件計算量(引用這些關聯表字段)的時間。因為有了部分預關聯,維表之間關聯運算本身不再消耗時間,而維表與lineitem表關聯的時間,也因為事先建好索引而提高了效能(可以減少一半的hash計算)。
測試結果彙總:
執行時間(秒)
兩表關聯
六表關聯
效能降低倍數
sql235
2669
11.4
spl預關聯
266472
1.8六表關聯比兩表關聯,sql慢了11.4倍,說明sql處理join消耗cpu很大,效能降低明顯。而採用部分預關聯機制後的spl只慢1.8倍,多join幾個表影響不大,效能不會明顯下降。
在進行關聯表較多的查詢時,如果記憶體大到足以將除事實表之外的維表資料全部讀入記憶體,使用部分預關聯技術依然能有效地提公升計算效能!而關聯式資料庫用在關聯表很多的時候會發生資料庫引擎不會優化的問題,導致效能下降很嚴重。
效能優化技巧 預關聯
sql中join的效能是個老大難問題,特別是關聯表較多時,計算效能會急劇下降。sql實現join一般是採用hash分堆的辦法,即先計算關聯鍵的hash值,再將相同hash值的記錄放到一起再做遍歷對比。每乙個join都要做一輪這樣的運算。如果資料量相對於記憶體並不是很大,可以事先全部載入到記憶體中,那...
效能優化技巧 記憶體關聯計算
關聯動作會嚴重影響效能,spl支援記憶體預關聯,可以加快關聯動作,從而提公升效能。為了理解關聯動作對效能的影響,下面設計一套oracle關聯表,以及無關聯的寬表,並執行同樣的計算。關聯表的結構和關係如下 資料量 聯絡歷史表 百萬條 使用者表 十萬條 開戶網點 一萬條 商表 一萬條 計算目標 求通訊總...
前端效能優化 預載入
1.什麼是預載入 資源預載入是另乙個效能優化技術,我們可以使用該技術來預先告知瀏覽器某些資源可能在將來會被使用到。預載入簡單來說就是將所有所需的資源提前請求載入到本地,這樣後面在需要用到時就直接從快取取資源。2.為什麼要用預載入 在網頁全部載入之前,對一些主要內容進行載入,以提供給使用者更好的體驗,...