天天看點

加速JDBC的快捷方法

JAVA 應用必須通過 JDBC 從資料庫中取數,有時候我們會發現,資料庫的負擔一點也不重而且 SQL 很簡單,但取數的速度仍然很慢。仔細測試會發現,性能瓶頸主要在 JDBC 上,比如 MySQL 的 JDBC 性能就非常差,Oracle 也不好。但是,JDBC 是資料庫廠商提供的包,我們在外部沒辦法提高性能。

可以想到的辦法是利用多 CPU 手段采用并行方案來提速,但 Java 的并行程式非常難寫,要考慮資源共享沖突等麻煩事務。

下面介紹使用集算器的并行技術來提升資料庫 JDBC 取數性能,可以避免 JAVA 寫死的複雜性,還能夠友善實作多線程結果集的合并。适用于:

源資料規模較大的查詢報表

多資料集報表

ETL 資料抽取

集算器并行配置

通過集算器進行并行取數前需要配置集算器的并行屬性。IDE 中通過菜單“工具 - 選項”設定 IDE 支援的最大并行數量,一般建議最大并行數不要超過 CPU 核數。

加速JDBC的快捷方法

集算器服務端則需要修改 raqsoftConfig.xml 配置:

加速JDBC的快捷方法

單表并行取數

有時我們查詢的某個表資料量較大、時間較長,這時就可以通過集算器針對單表并行取數提升性能。這裡所謂的單表是指通過條件并行讀取一份(單表)資料。

全記憶體

假設記憶體可以容納全部要讀取的資料,并行取數後再進行下一步運算(全記憶體的計算速度最快)。

舉例

訂單(Orders)有訂單 ID,訂購日期,訂單金額等字段,其中訂單 ID 是遞增的整數邏輯主鍵。

加速JDBC的快捷方法

【計算目标】 并行讀取某時間段内訂單數

面向單表(單條 SQL)并行取數需要通過參數将源資料拆分多段,建立多個資料庫連接配接并行查詢。往往需要将資料盡可能平均拆分以避免查詢時間不均導緻任務等待,同時分段參數盡可能建立在索引字段上以保證分段效率。

集算器實作

集算器參數

根據查詢時間段建立腳本參數,查詢起止日期

加速JDBC的快捷方法

分段政策(一)基于索引字段分段

加速JDBC的快捷方法

基于單表(單 SQL)并行取數前需要進行資料分段,盡量保證每個分段的資料平均。而分段參數盡量基于建立索引的字段(如訂單編号)。之是以要使用索引字段來分段,是因為使用索引并不會真地周遊整個表,而是直接定位,當資料量較大時優勢明顯。

集算器腳本

編寫并行取數腳本,這裡按照建立索引的訂單編号進行分段:

腳本解析:

1、A2 根據查詢起止日期獲得最大訂單編号和最小訂單編号,用于後面分段

2、B2-C2 将最小訂單号和最大訂單号分别指派給變量 b 和 e

加速JDBC的快捷方法

3、A3 設定并行數,使用并行取數前應檢查集算器的并行數配置以及授權中對并行數量的許可

4、A4-A5 根據起止訂單編号和并行數計算每個并行任務的起止分段參數(序列)

加速JDBC的快捷方法

5、通過 fork 啟動多個(4 個)線程,參數為分段起止參數序列,這裡可以看到 fork 啟動的線程數與參數序列成員數相同。在集算器中,經常将序表、序列作為參數值參與運算,非常友善

6、B7 為每個線程(子任務)建立資料庫連接配接,需要注意連接配接必須在 fork 子句中建立,以便為多線程分别使用,若共用一個連接配接無法起到加速取數的效果,資料庫會自動把同一連接配接上的多個請求改為串行執行。是以隻有當資料庫負擔不重,有足夠多連接配接可用時才可以使用并行取數提升性能

7、B8 分别查詢每個分段資料,查詢結果傳回到 A6 格。這裡 fork 子句直接傳回查詢結果(子句最後一行),如果想傳回其中某個或某幾個計算值可以顯示使用 return 關鍵字傳回子線程計算結果

8、傳回結果的 A6 格結果,4 個線程傳回 4 個結果集

9、A9 合并所有子線程查詢結果,以便進行下一步計算

基于索引字段進行資料分段,并且資料分段比較平均時,使用多線程并行查詢資料庫幾乎可以獲得線程數倍(線性)的性能提升。

分段政策(二)基于非索引字段分段

如果資料庫負擔不重時,也可以基于非索引字段進行分段(如日期),相對 JDBC 取數時間,多次周遊庫表時間也并不是很大,而這樣做的好處是不需要事先查詢資料庫以确定起止段界(如最大最小訂單編号)。

加速JDBC的快捷方法

與上述使用索引字段訂單 ID 分段不同,這裡使用非索引字段訂購日期進行分段。設起止日期為:2012-01-01 和 2015-12-31。

1、A2 計算起止日期查詢參數間隔天數,用于分段;interval 函數還可以計算年、季度、月、時、分、秒等間隔,用于日期時間處理很友善

2、A3-A5 根據并行數和日期間隔計算分段起止參數序列

3、A6 根據參數序列啟動多線程,B8 完成查詢并将結果傳回到 A6 格,A9 合并查詢結果

分段政策(三)并行線程數多于 CPU 核數

前面我們提到:建議并行任務數不要超過 CPU 核數,因為更多的任務數并不會增加并行度,而且還可以避免 CPU 進行線程切換帶來的額外時間開銷。但有時也可以将任務數設定到遠大于 CPU 核數,可以設定為 CPU 核數的倍數個,這樣多 CPU 負載也可以達到動态平衡,而且某些計算還可以簡化分段。如上述例子中,若隻查詢某一年資料就可以把線程數設定為 12(月),進而簡化分段。

集算器提供了多線程任務動态平衡機制,當任務數大于并行數配置時,集算器會自動為計算結束的線程配置設定下一個任務,這時可以保證某個線程會多跑幾個小任務,另一個線程隻跑少量大任務,達到總體平衡,而不必拘泥于必須把資料量平均配置設定。

加速JDBC的快捷方法

1、A1 根據 1 到 12 的序列啟動 12 個線程

2、B3 每個線程查詢一個月的資料并傳回結果到 A1

關于 fork 語句

在集算器中,通過 fork 語句可以啟動多個線程實施并行計算,而且集算器還提供了多種 merge 函數可以很友善合并并行結果,十分友善。

外存

有時某一條語句(一個表)的資料量較大,分段後并行子任務仍然無法全部加載到記憶體中,這時需要使用集算器提供的外存計算機制,基于遊标查詢資料。

沿用上面的例子,假設分段後的資料量很大需要使用遊标分批讀取處理資料。

加速JDBC的快捷方法

1、B8 建立資料庫遊标,查詢并不真正取數,多個遊标傳回到 A6 格

加速JDBC的快捷方法

2、A9 合并多路遊标,接下來就可以當做一個遊标繼續使用

3、A10 基于遊标,将查詢資料分批寫入檔案中。因為各個線程的運作速度無法保證規律性,是以基于多線程導出資料時次序不可控,對資料順序有要求時不能使用這個方法。

基于外存遊标并行查詢與全記憶體方式非常類似,當記憶體資源較緊張時可以通過外存計算的方式減少記憶體占用。

多表并行取數

除了通過條件針對單條 SQL(單表)進行并行取數外,在一些多 SQL 查詢場景(如報表多資料集)下仍然可以通過并行同時執行多條語句進行取數。

有多個查詢 SQL 基于多個表查詢資料,需要提升查詢性能。

【計算目标】 并行讀取 5 個表資料,并完成關聯

這裡我們使用 5 條非常簡單(基于單表)的查詢 SQL,實際業務中多條SQL 可以任意複雜。

加速JDBC的快捷方法

1、A2-A6 為查詢用 SQL 語句串

2、A7 根據多條 SQL 組成序列啟動多線程(5 個)

3、B9 每個線程執行 SQL 查詢資料将結果傳回到 A7 格(5 個結果集組成的序列)

4、A10-C11 通過序号分别擷取 5 個結果集

5、為了保證完整性,A12-A14 對 5 個結果集進行關聯并通過外鍵屬性化的方式建立結果序表

以上是集算器并行取數的部分示例,事實上集算器還可以做更複雜的并行計算和結果歸并。集算器多線程并行的意義在于使用簡單、成本低,相對 JAVA 複雜的多線程程式設計集算器可以簡單到幾行腳本,相對資料庫叢集方案集算器的成本更加可控,而且即使部署資料庫叢集仍然可以使用集算器加速叢集單個資料庫節點的取數速度。

作者:lisongbo

連結:

http://c.raqsoft.com.cn/article/1533291083840

來源:乾學院

著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。