【摘要】
數據分析場景中,充斥着聚合運算,常見的有求和、計數、均值、最大最小值等等,想要獲得正確的結果值,遍歷技術必不可少,如何更加高效地對數據進行遍歷?點擊:性能優化技巧 - 遍歷,來乾學院一探究竟!java
集文件是行存方式,組表有行存和列存兩種方式。兩種格式都有必定壓縮效果。性能優化
首先,咱們來創建一個的普通的文本文件,並在該文件中生成一些數據,代碼以下:函數
代碼1.1性能
代碼 1.1,生成一個 txt 文件,總記錄數爲 1000 萬,其中部分數據如圖 1.1 所示。測試
圖1.1fetch
代碼1.2優化
代碼1.3spa
代碼1.4對象
代碼 1.二、1.三、1.4 分別使用代碼 1.1 創建的 txt 文件,轉爲集文件 employee.btx、列存組表文件employee.ctx和行存組表文件employee@r.ctx,各文件大小如圖 1.2 所示。排序
圖1.2
按照文件佔用的硬盤空間大小排序能夠獲得:txt> 行存組表 > 集文件 > 列存組表。可見,一樣的數據,在不一樣的文件存儲格式下,所佔用的硬盤空間大小也不一樣,而文件的大小又會直接影響遍歷的效率。
排序能有效提升列存組表壓縮效率,重複次數多的字段排到前面。
代碼1.5
代碼1.5對原組表文件的level,height,weight,city列依次進行排序。
排序後的組表文件 employee_sort.ctx與原始文件employee.ctx相比,明顯變小,如圖1.3所示。
圖1.3
序表過濾時用 select@m 能夠並行計算。
代碼2.1
代碼2.1 中:
A二、A5 分別是外存的串行和並行狀況,耗時分別爲 2742 毫秒和 828 毫秒。
A九、A12 分別是內存的串行和並行狀況,耗時分別爲 1162 毫秒和 470 毫秒。
集文件和組表上均可以定義多路遊標實現並行遍歷。列存 + 機械硬盤 + 取用列過多時多路遊標不必定會更快。
代碼2.2
代碼2.2中:
前 3 行是集文件的並行遍歷,耗時 1861 毫秒。
後 5 行是相同數據的列存組表多路遊標並行遍歷。耗時 2282 毫秒。
使用 fork 語句並行時,不要返回遊標。遊標只是定義並無實際取數,這種並行沒有意義。要在 fork 代碼塊中作 fetch 或 groups 等實質取數的動做纔有意義。
代碼2.3
代碼2.3,前6行在fork代碼塊中完成fetch取數,而後合併結果,查詢耗時865毫秒。第7行至12 行,fork 返回遊標後,合併再進行 fetch 動做,耗時 1709 毫秒。
多個條件 && 時注意書寫次序,若是前面的子項爲假時,後面就不會再計算了,這樣把容易爲假的條件項寫到前面,會減小後面條件項的計算次數。
代碼3.1
代碼3.1:
A3 中的條件爲salary < 10010 && like(name,"*d*"),前面的子項返回結果集較小,查詢耗時748 毫秒。
A6 中的條件爲like(name,"*d*") && salary < 10010,前面的子項返回結果集較大,查詢耗時1814毫秒。
在集合中找成員時(IN 判斷),避免在過濾條件中臨時計算這個集合。集合成員較多時要先排序,而後用 pos@b 或 contain@b 去判斷,將使用二分法。
代碼3.2
在代碼3.2中:
A1:取 100 個範圍在 1 至 1000000 中的隨機數;
A2:爲確保後續測試的數據一致,將這 100 個隨機數存到文件 keys.txt 中。
代碼3.3
在代碼3.3中:
A2:將預先準備的每一個鍵值都乘以 10。
A5:使用 pos 函數在組表文件 employee.ctx 中找知足 A2 的成員並取出,耗時 15060 毫秒。
代碼3.4
在代碼3.4中:
與代碼3.3 的區別在於,把代碼 3.3 中 A2 的集合搬到了代碼 3.4 中 A4 的 cursor 過濾條件中臨時計算這個集合,執行耗時 32105 毫秒。相比代碼 3.3,雖然結果一致,但耗時多了一倍,應當避免這種寫法。
代碼3.5
代碼3.5,基於代碼3.3,咱們還能夠再進行一些優化。
將代碼3.3 的 A2 排序,獲得了有序鍵值。
在A5 中的 pos 函數採用選項 @b,使用二分法。執行耗時 7854 毫秒,相比代碼 3.3 快了將近一倍。
switch@i@d 可用於快速實現鍵值過濾,hash 索引經常會比二分法更有效。
代碼3.6
代碼3.6 中:
A5:使用switch@i過濾出知足序列A2中的數據,結果與代碼3.三、代碼 3.四、代碼 3.5 一致,耗時爲 7104 毫秒。switch函數時會自動建索引@d選項也能夠實現過濾效果,這裏再也不單獨例舉。
組表遊標在建立時便可寫入一些過濾條件。集算器會識別這些條件,利用組表自己的排序信息快速跳到相應的數據位置。另外,這些條件不知足時取出字段就不會被讀出,能夠減小對象產生次數。而已經產生了遊標後再作過濾就沒有這些效果了。咱們來看這樣一個例子。
代碼4.1
代碼 4.1 中:
A3 在組表遊標建立時寫入過濾條件 level=="one" && height<180 而且只取 city 和 sex 兩列數據。
A7 在組表遊標建立後,再經過 select 中的過濾條件篩選數據。
隨後二者進行了相同的分組聚合運算,結果前者耗時1206 毫秒,後者耗時 4740 毫秒。
遊標取數性能和每次取出的記錄數相關,要作些測試,通常最好是幾萬行,不要一次只取一行。
代碼5.1
代碼 5.1 中:
代碼經過遍歷組表遊標,獲取結果,並累計每次結果的記錄數。
前6行遍歷過程當中每次取10條記錄,最終累計耗時7823毫秒。
後6行遍歷過程當中每次取50000條記錄,最終累計耗時3923毫秒。
還可使用 skip 函數計數,這樣沒必要把遊標數據讀出產生成 java 對象。
代碼5.2
代碼 5.2 中:
A3 在建立組表遊標時取第一列,而後取出該列數據後取得其長度。
A6 對組表遊標使用 skip 函數,獲取該組表記錄數。
這兩個單元格計算後的值都爲 10000000,但前者耗時 9676 毫秒,後者耗時 6473 毫秒。
使用管道技術能夠對基於同一次遍歷計算出多個結果,減小硬盤的訪問。
代碼6.1
代碼 6.1 中:
A二、B二、C2 分別是組表遊標 A1 上創建的管道,A三、B三、C3 爲這三個管道定義不一樣篩選條件並定義取數,A6 中遍歷組表遊標,每次取 100000 條。A六、B六、C6 返回按前文定義的篩選條件返回的結果集。耗時 5182 毫秒。
第9 行的三個單元格沒有使用管道,分別三次創建組表遊標再按前文三個相同的篩選條件取出結果。耗時 12901 毫秒。(關於管道的使用,新版本中還有更優寫法,代碼簡潔明瞭,歡迎各位讀者自行體驗集算器語法的優雅之處。)" rel="nofollow">性能優化技巧 - 遍歷,來乾學院一探究竟!