4種提高多維數據分析的方法
譯文【51CTO.com快譯】聯機分析處理(OLAP)需要有即時的響應,因此其性能是至關重要的。雖然其結構較為簡單,但是在處理各種大的數據立方體(data cubes)時,會涉及到大量的計算。
常被稱為OLAP(聯機分析處理)的多維分析是一種交互式的數據分析過程,它包括:對于數據立方體(data cube)進行旋轉(rotation)、切片與切塊(slice and dice)、鉆取(drill-down)等執行操作。其后端的計算結構較為簡單,如下列SQL語句所示。
- SELECT D,..., SUM(M), ... FROM C WHERE D'=d' AND ... GROUP BY D,...
該語句通過多個維度(dimension)聚合了各種量度(measure)。其中C是一個數據立方體,D,…表示所選的維度,而M,…則代表用于聚合的各個量度。除了SUM,我們也可以使用其他的聚合函數。D'是一個切片維度。切塊操作的范圍標準,用語句D IN (d,...)來表示。我們還可以在量度中定義一個規則,用WHERE語句來選擇一定范圍內的值。
OLAP分析需要即時的響應,因此高性能是至關重要的。盡管該語句的結構較為簡單,但是當我們處理各種大的數據立方體時,則可能會涉及到大量的計算。而在我們能夠找到一種優化它們的方法之前,其分析過程一般比較緩慢的。以下我們列出了幾種能夠為多維分析提高后端性能的常見方法。
1. 預聚合(Pre-Aggregation)
早期的OLAP產品通常會采用預聚合作為一種有效地交換存儲開銷的方法。該方法通過一些或者所有的維度(在GROUP BY語句中被定義),預先計算聚合的值(在SELECT查詢的各種量度中被定義),并且存儲它們。這些中間結果可以直接被后期的計算所使用到,或是產生一些新的計算。通過這種方式,性能方面能夠大幅地提升。
這些聚合的結果會占用大量的空間。通常情況下,可能會有幾十個維度,而每個維度值的范圍則從一位數到兩位數不等。簡單的數學運算表明:預聚合的結果將比原始數據立方體大幾倍到幾十倍(也就是說:如果考慮到各種類型的聚合函數的話,其比例為(k1+1)*(k2+1)*...到k1*k2*...)。盡管數據立方體不會因為太大而無法獲得即時地響應,但是這個增大幾十倍的數據量還是不可能實現的。
有一個折中的方法是僅計算其中一些維度的聚合值。因為只有少數的分組維度(在GROUP BY語句中被定義)會被顯示在OLAP的接口中,所以我們能夠以m的維度來執行聚合。如果m的值不大于5,則存儲的開銷將在一個合理的范圍內,而大部分的用戶操作也將能得到快速地響應。
當然,部分聚合是不能使用其他維度的切片標準來處理的。然而,鉆取卻正好是基于切片的。這就糟糕地導致了:即使是那些對于多維分析來說并非少見的且廣泛使用的聚合,也無法使用同一個量度來處理某個切片標準(比如說,要獲得超過¥1000的銷售額)。因此,一個聚合函數很可能僅僅包含一個標準(比如說,只是低于¥100的總成本)。可見,預聚合的結果對于所有這些場景都是無用的。
預聚合只能處理一些最為常見的場景,而這些只在所有類型的多維分析場景中占有一小部分。而全量遍歷(full traversal)則仍然在大多數的場景中被用到。
2. 基于段的并行處理(Segment-Based Parallel Processing)
從本質上講,多維分析就是對數據的過濾和分組,這就很容易實現并行處理。它的步驟包括:將數據劃分為多個段,分別處理它們,并收集那些相互獨立的子任務(subtask)所處理的結果,從而進行聚合。無論是在單臺機器上,還是在多節點集群的計算上,甚至是兩者的結合,其多線程處理都不難以被實施。
雖然多維分析的結果是可視化的,但是我們用肉眼所能看到的數據還是遠低于現代計算機內存里所能夠保存的數據。對于一個足夠小的數據集,它能夠很容易地被加載到內存中,而不需要在內存和磁盤之間進行交換。其編程也相對比較簡單,且性能優秀。不過,在一個計算過程中生成的大數據集則會被直接提交給接口,其計算隨即被中止掉。
根據我們的測試,如果所有在同一個多線程處理的子任務,合并它們的結果到一個相同的結果集里,其性能則可能會由于多個線程使用單一的資源進行同步操作,而受到嚴重的影響。可見,通過使用共享的最終數據集,內存的占用會有所減少。
更多的線程并不一定總是更好的,當線程超過CPU內核數時它就變得無效了。對于存放在外部存儲設備中的數據而言,為了獲取多線程處理的實際結果,測試是必要的。因為硬盤的并發能力(通常會小于CPU內核的數量),需要被考慮到。
根據記錄的數量和每一段結束處的標記,來劃分靜態數據是很容易的。但是如果要平均地劃分動態數據就比較麻煩了。本文將在下面更詳細地予以討論。
對于一個單一的計算任務而言,并行處理能夠帶來性能上的成倍增加。而由于OLAP的操作基本就是一個并發的事務,其提高了的性能在用戶的數量很小的情況下可能會被抵消掉。因此我們需要有一種更好的方法。
3. 排序索引(Sorted Index)
因為非切片式的聚合操作總會牽扯到整體的數據立方體,所以我們幾乎無法通過執行預聚合來減少計算量。但是對于切片操作(鉆取)來說,如果數據立方體已經被排序,則沒有必要去做全量遍歷了。
如果我們能為D維度創建一個索引,這就意味著將它的值與對應的序列號記錄關聯上了,并形成了一定的排列順序。然后我們就能夠快速地定位那些包含在D維度里符合切片標準的記錄了。這是一個簡單的二分查找。無需全量遍歷所有的數據,其計算量將能夠降低好幾個數量級(這也取決于D的取值范圍)。理論上說,我們可以為每個維度創建一個索引,因為其開銷并不昂貴。而且在涉及到相應的切片時,其性能會有大幅提升。
不過,那種包含有D1和D2維度的多個字段索引實際上卻鮮少被用到。因為它不能快速地定位到只包含D2維度的切片,它只是對同時包含D1和D2的切片非常有效。在定位到了記錄一個包含著***取值范圍的維度切片之后,大量的計算將會被相應地大幅減少。當然,我們也可以通過他們的維度去遍歷其他的切片。
不幸的是,這種原始的方法只適用于處理那些允許頻繁、小額存取的內存中的數據。在大多數情況下,我們要處理的數據集還是相當大的,而且需要存儲在磁盤之上。但是就算通過索引,檢索那些大量無序記錄的操作對于性能提升影響也不很大。數據只有在被真正排序,和切片里的記錄在被連續存儲時,其性能才會有明顯的提升。
由于各種數據需要根據特定維度的排序目的來進行復制,因此其成本還是相當高的。
有一個用來創建兩份數據拷貝的解決方案是:一處的數據按照D1,…,Dn維度進行排序,而另一處的數據則按照Dn,…,D1維度來排序。由此產生的數據量只是原來的兩倍,這還是可以接受的。通過該二維序列,就有了一處切片維度總是從首部開始降序排列的,確保了此維度的切片數據在整體上是連續的,從而能夠獲得了更好的性能提高。
4. 壓縮列式存儲(Compressed Column Storage)
處理多維分析的一個強大工具是:列式存儲。
通常情況下,我們在對數據立方體進行多維分析時,會有大量的字段(維度和測度),他們從數十到數百不等。但是其中真正有用的卻并不多,如果不考慮切片維度的話,通常也就只有5個或更少。由于切片能夠被索引來進行處理,那么只需要對某幾個字段遍歷便可。
基于這個考慮,列式存儲正好可以發揮其優勢。在外部存儲的計算中,I/O的操作是非常耗時的。因此,與減少計算的數量相比,減少要檢索的數據以提升性能就顯得更有意義了。比如說一個具有100個字段的數據立方體,如果只檢索五個字段的話,其I/O消耗將下降到原來的二十分之一,這會導致性能的數量級飆升。
列式存儲的另一個優點是:它支持數據的壓縮。在排序和存儲數據的D1,…,Dn維度時,我們發現D1在一連串的記錄中有著相同的值;而D2在一個較少的連續記錄中也是如此;以此類推,在越來越少的連續記錄中,都會有這樣的相同值出現;直到Dn中幾乎沒有了這樣的連續性??紤]我們沒有必要去存儲那些反復出現的連續相同值,我們完全可以一次性存儲,并記錄下它們的數字。通過這種減少數據占用空間的方法,我們就能減少對外部存儲的I/O訪問,并提高性能。
在使用列式存儲時,我們還需考慮如下一些問題。
由于列式存儲不會減少計算的數量,它對在內存中操作數據的幫助并不大。但其壓縮存儲的方案卻能夠有效地減少內存的消耗。
列式存儲會復雜化基于段的并行處理和索引的創建。列的分割需要保持彼此的一致性,而索引則需要同時地且準確地參考所有的列。而當使用壓縮的列式存儲時,則會更加麻煩。雖然有這些繁瑣的問題,但是一般來說,對于靜態數據使用列式存儲并不是太難(只是不要忘了對它們的處理)。
列式存儲的使用會增加并發壓力的風險。當字段的總數不多或我們需要檢索太多的字段時,它會失去本身的優勢。通過硬盤來額外地使用并行處理,將會進一步地增加并發的壓力,也可能會導致性能的下降。因此,能夠更好地支持并發性的SSD會更適用一些。
原文標題:4 Ways to Improve Multidimensional Data Analysis 作者: Buxing JIANG
【51CTO譯稿,合作站點轉載請注明原文譯者和出處為51CTO.com】