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