性能優化技巧 - 遍歷

【摘要】
數據分析場景中,充斥着聚合運算,常見的有求和、計數、均值、最大最小值等等,想要獲得正確的結果值,遍歷技術必不可少,如何更加高效地對數據進行遍歷?點擊:性能優化技巧 - 遍歷,來乾學院一探究竟!java

1. 存儲方案

集文件是行存方式,組表有行存和列存兩種方式。兩種格式都有必定壓縮效果。性能優化

首先,咱們來創建一個的普通的文本文件,並在該文件中生成一些數據,代碼以下:函數

image.png

代碼1.1性能

代碼 1.1,生成一個 txt 文件,總記錄數爲 1000 萬,其中部分數據如圖 1.1 所示。測試

圖1.1fetch

image.png

代碼1.2優化

image.png

代碼1.3spa

image.png

代碼1.4對象

代碼 1.二、1.三、1.4 分別使用代碼 1.1 創建的 txt 文件,轉爲集文件 employee.btx、列存組表文件employee.ctx和行存組表文件employee@r.ctx,各文件大小如圖 1.2 所示。排序

 

圖1.2

按照文件佔用的硬盤空間大小排序能夠獲得:txt> 行存組表 > 集文件 > 列存組表。可見,一樣的數據,在不一樣的文件存儲格式下,所佔用的硬盤空間大小也不一樣,而文件的大小又會直接影響遍歷的效率。

排序能有效提升列存組表壓縮效率,重複次數多的字段排到前面。

image.png

代碼1.5

代碼1.5對原組表文件的level,height,weight,city列依次進行排序。

排序後的組表文件 employee_sort.ctx與原始文件employee.ctx相比,明顯變小,如圖1.3所示。

圖1.3

2. 並行遍歷

序表過濾時用 select@m 能夠並行計算。

image.png

代碼2.1

代碼2.1 中:

A二、A5 分別是外存的串行和並行狀況,耗時分別爲 2742 毫秒和 828 毫秒。

A九、A12 分別是內存的串行和並行狀況,耗時分別爲 1162 毫秒和 470 毫秒。

集文件和組表上均可以定義多路遊標實現並行遍歷。列存 + 機械硬盤 + 取用列過多時多路遊標不必定會更快。

image.png

代碼2.2

代碼2.2中:

前 3 行是集文件的並行遍歷,耗時 1861 毫秒。

後 5 行是相同數據的列存組表多路遊標並行遍歷。耗時 2282 毫秒。

使用 fork 語句並行時,不要返回遊標。遊標只是定義並無實際取數,這種並行沒有意義。要在 fork 代碼塊中作 fetch 或 groups 等實質取數的動做纔有意義。

image.png

代碼2.3

代碼2.3,前6行在fork代碼塊中完成fetch取數,而後合併結果,查詢耗時865毫秒。第7行至12 行,fork 返回遊標後,合併再進行 fetch 動做,耗時 1709 毫秒。

3. 過濾條件

多個條件 && 時注意書寫次序,若是前面的子項爲假時,後面就不會再計算了,這樣把容易爲假的條件項寫到前面,會減小後面條件項的計算次數。

image.png

代碼3.1

代碼3.1:

A3 中的條件爲salary < 10010 && like(name,"*d*"),前面的子項返回結果集較小,查詢耗時748 毫秒。

A6 中的條件爲like(name,"*d*") && salary < 10010,前面的子項返回結果集較大,查詢耗時1814毫秒。

在集合中找成員時(IN 判斷),避免在過濾條件中臨時計算這個集合。集合成員較多時要先排序,而後用 pos@b 或 contain@b 去判斷,將使用二分法。

image.png

代碼3.2

在代碼3.2中:

A1:取 100 個範圍在 1 至 1000000 中的隨機數;

A2:爲確保後續測試的數據一致,將這 100 個隨機數存到文件 keys.txt 中。

image.png

代碼3.3

在代碼3.3中:

A2:將預先準備的每一個鍵值都乘以 10。

A5:使用 pos 函數在組表文件 employee.ctx 中找知足 A2 的成員並取出,耗時 15060 毫秒。

image.png

代碼3.4

在代碼3.4中:

與代碼3.3 的區別在於,把代碼 3.3 中 A2 的集合搬到了代碼 3.4 中 A4 的 cursor 過濾條件中臨時計算這個集合,執行耗時 32105 毫秒。相比代碼 3.3,雖然結果一致,但耗時多了一倍,應當避免這種寫法。

image.png

代碼3.5

代碼3.5,基於代碼3.3,咱們還能夠再進行一些優化。

將代碼3.3 的 A2 排序,獲得了有序鍵值。

在A5 中的 pos 函數採用選項 @b,使用二分法。執行耗時 7854 毫秒,相比代碼 3.3 快了將近一倍。

switch@i@d 可用於快速實現鍵值過濾,hash 索引經常會比二分法更有效。

image.png

代碼3.6

代碼3.6 中:

A5:使用switch@i過濾出知足序列A2中的數據,結果與代碼3.三、代碼 3.四、代碼 3.5 一致,耗時爲 7104 毫秒。switch函數時會自動建索引@d選項也能夠實現過濾效果,這裏再也不單獨例舉。

4. 預先過濾

組表遊標在建立時便可寫入一些過濾條件。集算器會識別這些條件,利用組表自己的排序信息快速跳到相應的數據位置。另外,這些條件不知足時取出字段就不會被讀出,能夠減小對象產生次數。而已經產生了遊標後再作過濾就沒有這些效果了。咱們來看這樣一個例子。

image.png

代碼4.1

代碼 4.1 中:

A3 在組表遊標建立時寫入過濾條件 level=="one" && height<180 而且只取 city 和 sex 兩列數據。

A7 在組表遊標建立後,再經過 select 中的過濾條件篩選數據。

隨後二者進行了相同的分組聚合運算,結果前者耗時1206 毫秒,後者耗時 4740 毫秒。

5. 遊標取數

遊標取數性能和每次取出的記錄數相關,要作些測試,通常最好是幾萬行,不要一次只取一行。

image.png

代碼5.1

代碼 5.1 中:

代碼經過遍歷組表遊標,獲取結果,並累計每次結果的記錄數。

前6行遍歷過程當中每次取10條記錄,最終累計耗時7823毫秒。

後6行遍歷過程當中每次取50000條記錄,最終累計耗時3923毫秒。

還可使用 skip 函數計數,這樣沒必要把遊標數據讀出產生成 java 對象。

image.png

代碼5.2

代碼 5.2 中:

A3 在建立組表遊標時取第一列,而後取出該列數據後取得其長度。

A6 對組表遊標使用 skip 函數,獲取該組表記錄數。

這兩個單元格計算後的值都爲 10000000,但前者耗時 9676 毫秒,後者耗時 6473 毫秒。

6. 遍歷複用

使用管道技術能夠對基於同一次遍歷計算出多個結果,減小硬盤的訪問。

image.png

代碼6.1

代碼 6.1 中:

A二、B二、C2 分別是組表遊標 A1 上創建的管道,A三、B三、C3 爲這三個管道定義不一樣篩選條件並定義取數,A6 中遍歷組表遊標,每次取 100000 條。A六、B六、C6 返回按前文定義的篩選條件返回的結果集。耗時 5182 毫秒。

第9 行的三個單元格沒有使用管道,分別三次創建組表遊標再按前文三個相同的篩選條件取出結果。耗時 12901 毫秒。(關於管道的使用,新版本中還有更優寫法,代碼簡潔明瞭,歡迎各位讀者自行體驗集算器語法的優雅之處。)" rel="nofollow">性能優化技巧 - 遍歷,來乾學院一探究竟!

相關文章
相關標籤/搜索