內容來源:本文轉載自數據蔣堂公衆號,經受權發佈!
性能優化
閱讀字數:2969 | 5分鐘閱讀多線程
多維分析法是高級統計分析方法之一,就是把一種產品或一種市場現象,放到一個兩維以上的空間座標上來進行分析。併發
多維分析就是針對一個事先準備好的數據立方體實施旋轉、切片(切塊)、鑽取等交互操做的過程,常常也被直接稱爲OLAP。它的後臺運算在結構上很簡單,若是用SQL語法描述,大致形式爲:函數
SELECT D,..., SUM(M), ... FROM C WHERE D'=d' AND ... GROUP BY D,...
性能
即對立方體按某些維度分組彙總某些測度。其中C是數據立方體,D,...是選出維度,M,...是聚合測度,聚合函數也能夠不是SUM。D'是切片維度,切塊時條件爲D IN (d,...),WHERE中還能夠增長針對某些測度的條件,通常也就是選出某個區間內的值。測試
OLAP須要即時響應,對性能要求很高,而這個運算形式雖然很簡單,但數據量大時的計算量也不小,若是不設法優化,效率就可能不好。下面咱們介紹多維分析後臺建設時幾種常常被採用的性能優化手段。優化
預先匯老是早期OLAP產品經常使用的手段,簡單地就是拿空間換時間。把部分或者所有維度組合(GROUP BY子句)的彙總值(SELECT中的聚合測度)先計算出來保存,之後的計算能夠直接取出或從這些中間結果再計算,性能會好不少。線程
預先彙總佔用的空間有點大。若是保存所有維度組合,通常應用場景下(十幾到幾十個維度,維度取值範圍在幾到幾十之間),簡單計算可知,空間佔用會比原始立方體大數倍到數十倍((k1+1)*(k2+1)*...與k1*k2*...之間的比,還要考慮多種聚合函數)。雖然要保證即時響應時立方體都不會太大,但再大幾十倍常常也仍是難以接受的。設計
折衷辦法是隻保存部分維度組合。OLAP過程當中在界面上呈現出來的分組維度(GROUP BY子句)不會太多,能夠只彙總全部m個維度的組合,在m不太大時(通常不超過5),空間增加還能夠容忍,而用戶的大多數操做均可以獲得較迅速響應。code
麻煩在於,部分彙總解決不了針對其它維度的切片條件,鑽取動做就是以切片爲基礎的。並且,即便全量彙總也沒法處理測度上的條件(好比銷售額超過1000元的統計),而多維分析時經常容許這些動做,甚至聚合函數也可能帶有條件(只合計100元如下的費用),這些都沒法使用預先彙總的結果。
預先彙總只能解決小部分最多見的計算,更多的狀況仍是要靠硬遍歷。
多維分析本質上是過濾和分組彙總,這種運算很容易並行。只要簡單地數據拆成多段後分別處理,收集到結果再彙總。各個子任務之間沒有依賴關係,不管是單機多線程仍是集羣多機或者綜合有之,都不難實現。
多維分析的結果是要呈現給人看的,而人能夠觀察的數據量遠遠小於現代計算機的內存。能夠放入內存的小結果集不須要和外存交換,程序設計複雜度較低,運算性能也好。若是運算時發現結果集太大是能夠直接報告給界面相應信息並停止。
實踐測試代表:多線程計算時,不要採用各子任務向同一個結果集彙總的方案,這樣看起來會減小內存佔用(各子任務共用一個最終結果集),但多線程搶佔同一資源須要的同步動做會嚴重影響性能。
線程數也不是越多越好,顯然超過CPU核數就沒有意義了。若是數據在外存,還要考慮硬盤的併發能力,通常會比CPU核數小不少,具體合適的數值須要實際測試才知道。
在數據再也不變化時分段也容易,按記錄數切分後設置分段點便可。數據可追加時要作到較平均的分段會有些麻煩,之後再另外撰文陳述。
對於單個計算任務,並行後經常有數倍的性能提高。可是,OLAP操做自己就是個併發性事務,即便用戶數不大,也足以抵消並行計算帶來的性能提高。
還要再想辦法。
沒有切片的彙總運算老是要涉及全量數據,若是不是預先彙總,也沒什麼辦法再減小計算量了。但有切片運算時(鑽取動做),若是數據能合理組織,就未必要遍歷全部數據了。
若是咱們爲維度D創建索引(即把各記錄的D值及記錄位置按D值排序),那麼涉及D的切片條件就能夠迅速定位到相應的記錄上(簡單二分法),不須要遍歷全量數據,計算量經常會有數量級的減小(取決於D的取值範圍)。理論上咱們能夠爲每一個維度都創建索引,這個成本並不算高,這樣只要涉及有切片時,性能就會大幅提高。
須要指明的是,爲多個維度D1,D2創建的多字段索引用處並不大,它不能用於迅速定位只有D2的切片,只能用於對D1,D2都有切片條件的狀況。在選擇取值範圍最大的那個切片維度用於定位後,計算量減小已經不少了,其它維度的切片能夠仍用遍歷手段。
不幸的是,這種原始方案只適用於能夠頻繁小量訪問的內存數據。若是數據量大到必須放在外存中(而這是常常發生的),按索引大量取出實際上並未連續存儲的數據時,性能並不會有明顯提升。外存數據必須被真實排序、保證相應切片的數據是連續存儲的,性能提高才會有效。
若是對每一個維度都作排序,那至關於數據要被複制若干倍,這個成本就有點高了。
一個折衷的辦法是把作兩個,按維度D1,...,Dn排序一次,再按Dn,...,D1排序一次,數據量只是翻倍,還能容忍。總能找到一個切片維度在兩個維度排序列的前半部分,這樣該維度切片的數據仍是基本連續的,性能提高仍會較爲明顯。
對付多維分析還有個大殺器:列式存儲。
多維分析的立方體中字段(維度和測度)經常都不少,幾十個上百個都很正常,但同時須要取用的字段並很少,若是不算切片維度,一般也就5個左右或更少。而切片能夠用上面的索引方案解決,實際要遍歷的字段也仍然很少。
這時候列存就會有巨大優點了。外存計算的IO時間佔比至關大,減小數據讀取量比減小運算量經常能更有效地提升性能。一個100個字段的立方體,若是隻取5個字段時,IO開銷只有1/20,這會帶來數量級的性能提高。
列存還有個優點是能夠壓縮數據量。若是按前述所說將數據按維度D1,...,Dn排序存儲,咱們會發現D1在連續許多記錄中取值都相同,D2也是相似,但程度會弱一些,越日後的維度連續相同的程度越弱,Dn就會幾乎沒有相同連續值。連續相同的值不必重複存儲,能夠只存一次並記錄個數,這樣將能夠進一步減小存儲量,也就是減小外存IO訪問量,從而提升性能。
固然,列存也並不全是好處。
由於不減小計算量,列存對於內存數據用處不大。不過壓縮存儲方式仍然有意義,能夠減小內存佔用。
使用列存會使分段並行及創建索引的處理變得更復雜,各個列須要同步分段才能並行處理,索引也須要同步指向全部列,而使用壓縮機制後同步更爲麻煩。不過,總得來說,在數據已經肯定再也不變化時,雖然麻煩,但難度並不算大,只是別忘處理了就行。
列存還會加大硬盤的併發壓力,在總字段數很少或取用字段較多時並無優點。對於機械硬盤,若是再使用並行手段進一步加重併發壓力,極可能致使性能不升反降的結果,對於易於併發的固態硬盤使用列存較爲合適。