您好,登錄后才能下訂單哦!
大數(shù)據(jù)分析的性能優(yōu)化,說道底,就優(yōu)化一個事情:針對確定的一個計算任務(wù)(數(shù)據(jù)確定,結(jié)果確定),以最經(jīng)濟的方案得到結(jié)果。
這個最經(jīng)濟的方案主要考量三個成本:時間成本、硬件成本、軟件成本。
時間成本:根據(jù)計算任務(wù)的特點,能容忍的最長時間各不相同。那些 T+0 的計算任務(wù),實時性要求就比較高,T+1 再算出結(jié)果就失去了意義。
硬件成本:可以使用的硬件資源,對一個公司來說一般不是經(jīng)常變化的,機器配置、可集群數(shù)量就那么多。即便使用云計算產(chǎn)品,也只是多了擴容的靈活性,成本是少不掉的。
軟件成本:編寫出這個計算算法的人工費 + 軟件環(huán)境的成本。這個成本也與前兩項相關(guān),程序控制力度粗獷一些,實現(xiàn)邏輯簡單一些,程序就容易編寫,那軟件成本就會低一些,帶來的副作用是運行時間超長或者需要昂貴的硬件。
這三個因素里面,一般對于計算任務(wù)來說,自然是越快越好,當(dāng)然只要不慢過能容忍的時長,也就還算是有意義的計算;而硬件因素的彈性就比較小,有多少資源是相對固定的;所以,剩下的可以大做文章的就是軟件成本了。軟件成本里,程序員的工資是很重要的一項,而有沒有順手的軟件環(huán)境讓程序員能高效的把計算描述出來,就成了關(guān)鍵。最典型的例子就是理論上用匯編程序能寫出所有的程序,但它明顯不如 SQL 或 JAVA 做個常規(guī)計算來的容易。
說到 SQL 和 JAVA,成規(guī)模的計算中心的一些維護者估計也會皺眉,使用它們的時間越長,越能體會需求變動或優(yōu)化算法過程中的痛苦,明明算法過程自己想的很清楚了,但編寫成可運行的程序就困難重重。這些困難主要來自兩個方面:
首先,一些基礎(chǔ)的數(shù)據(jù)操作方法是自己逐漸積累的,沒有經(jīng)過整體的優(yōu)化設(shè)計,這些個人工具對個人的開發(fā)效率有不錯的提升,但沒法通用,也不全面,這個困難主要表現(xiàn)在用 JAVA 等高級語言實現(xiàn)的一些 UDF 上。
第二,主要是思維方式上的,在生產(chǎn)場景下用習(xí)慣了 SQL 查詢,在計算場景下遇到的性能問題自然而然就想通過優(yōu)化 SQL 語句的方式把問題緩解掉。但實際上這可能是個溫水煮青蛙的過程。越深入搞,把簡單的過程問題越可能搞成龐大不可拆分的邏輯塊,到最后只有原創(chuàng)作者或高手才敢碰它。我這個老程序員,十多年前剛?cè)胄械臅r候,八卦中耳聞過 ORACLE 的系統(tǒng)管理員,尤其是有性能優(yōu)化能力的,比普通程序員貴多了,可見這個難題在數(shù)據(jù)規(guī)模相對較小的十年前已經(jīng)凸顯了。
(注:生產(chǎn)場景和計算場景在初始階段的軟件系統(tǒng)里一般很難截然分開,數(shù)據(jù)都是從生產(chǎn)場景積累起來的,等積累多了,慢慢會增加計算需求,逐漸獨立出計算中心和數(shù)據(jù)倉庫。這個量變引起質(zhì)變的過程,如果不在思維上轉(zhuǎn)變,不引入新辦法,那就將成為被煮的青蛙。)
為了節(jié)省讀者的時間,我們先把性能優(yōu)化的常用手段總結(jié)一下,方便有需求的用戶逐條對比進行實際操作。
1、 只加載計算相關(guān)數(shù)據(jù)。
列存方式存儲數(shù)據(jù);
常用的字段和不常用的分開存儲;
用獨立的維表存儲維的屬性,減少事實表的信息冗余;
按照某些常用作查詢條件的字段分開存儲,如按年份、性別、地區(qū)等獨立存儲;
2、 精簡計算涉及到的數(shù)據(jù)
用來分析時,一些冗長的編號,可以序號化處理,用 1、2、……替代 TJ001235-078、 TJ001235-079、……,這樣即能加快加載數(shù)據(jù)的速度,又能加快計算速度。
日期時間,如果用字符串類型按照我們熟悉的格式 (2011-03-08) 存儲,那加載和計算都會慢。前面這個日期可以存儲成 110308 這樣的數(shù)值類型,也可以存儲成相對于一個開始時間的毫秒數(shù)(如相對于最早的數(shù)據(jù) 2010-01-01 的毫秒數(shù))。
3、 算法的優(yōu)化
計算量小的條件寫在前面,如 boolean 類型的判斷,要早于字符串查找,這樣用較少的計算就能排除掉不符合要求的數(shù)據(jù);
減少對大事實表的遍歷次數(shù)。具體方法有:在一次遍歷過程中,同時給多個獨立的運算操作提供數(shù)據(jù)(后面會提到的集算器里的管道概念),而不是每個運算操作遍歷一次數(shù)據(jù);做 JOIN 時,在內(nèi)存里的維表里檢索事實表數(shù)據(jù),而不是用每條維表數(shù)據(jù)去遍歷一次事實表。
查找時借用 HASH 索引、二分法、序號直接對位等方式加快速度。
4、 并行計算
加載數(shù)據(jù)和計算兩個步驟都可以并行??剂坑嬎闾攸c,根據(jù)加載數(shù)據(jù)和運算哪個量更大來判斷瓶頸是計算機的磁盤還是 CPU,磁盤陣列適合并行加載數(shù)據(jù),多核 CPU 適合并行運算。
多機集群的并行任務(wù),要考慮主程序和子程序的通訊問題,盡量把復(fù)雜計算獨立到節(jié)點機上完成,網(wǎng)絡(luò)傳輸較慢,要減少節(jié)點機之間的數(shù)據(jù)交換。
兵馬未動糧草先行,有了上面這些指導(dǎo)思想,我們下面就切入正題實現(xiàn)漏斗計算的優(yōu)化,看一下實際的優(yōu)化效果。
數(shù)據(jù):
程序:(附件中的 1-First.dfx,也附帶了測試數(shù)據(jù)文件,可在集算器里直接執(zhí)行)
漏斗轉(zhuǎn)換計算核心代碼的邏輯細節(jié)在上一篇中詳細介紹過,這里就不再贅述。
結(jié)果:(注:之后的測試都以 118 萬條數(shù)據(jù)為基礎(chǔ),成倍增加)
118 萬條記錄 /70MB/ 用戶數(shù)量 8000/31 秒;
590 萬條記錄 /350MB/ 用戶數(shù)量 4 萬 /787 秒。
分析:
數(shù)據(jù)量增加到 5 倍,但耗時增加到了 26 倍,性能下降得厲害,而且不是線性的。原因是被分析的用戶列表擴大了 5 倍,同時被分析的記錄數(shù)也擴大 5 倍,那檢索用戶次數(shù)理論上就擴大了 5*5 倍。接下來采用以下優(yōu)化方式↓
程序:(2-BinarySearch.dfx)
B12 給 find 增加 @b 選項,指明用二分法查找;D13 中卻去掉 insert 的第一個位置參數(shù) 0 后,新用戶就不直接追加到最后了,而是按主鍵順序插入。
A | B | C | D | |
11 | …… | |||
12 | for A11 | >user=A10.find@b(A12.用戶 ID) | ||
13 | if user==null | if A12.事件 ID==events(1) | >A10.insert(,A12.用戶 ID: 用戶 ID,1:maxLen,[[A12. 時間,1]]:seqs) | |
14 | …… |
結(jié)果:
118 萬條記錄 /70MB/ 用戶數(shù)量 8000/10 秒;
590 萬條記錄 /350MB/ 用戶數(shù)量 4 萬 /47 秒。
分析:
優(yōu)化后,1 倍的數(shù)據(jù)量耗時縮減到 1/3;5 倍的數(shù)據(jù)量提速比較明顯,縮減到 1/16。進一步觀察,5 倍數(shù)據(jù)量是 350MB,從硬盤載入數(shù)據(jù)的速度慢點算也會有 100M/ 秒,假如 CPU 夠快的話,極限速度應(yīng)該能到 4 秒左右,而現(xiàn)在的 47 秒證明 CPU 耗時還比較嚴重,根據(jù)經(jīng)驗可以繼續(xù)優(yōu)化↓
程序:(3-BatchReadFromCursor.dfx)
12~17 行整體剪切后,向右移一個格子之后,在 A12 增加一個批量加載游標數(shù)據(jù)的循環(huán),表示 A11 中的游標每次取 10000 條,B12 再對取出來的這 10000 條數(shù)據(jù)循環(huán)處理。
A | B | C | |
11 | …… | ||
12 | for A11,10000 | for A12 | …… |
13 | …… |
結(jié)果:
118 萬條記錄 /70MB/ 用戶數(shù)量 8000/4 秒;
590 萬條記錄 /350MB/ 用戶數(shù)量 4 萬 /10 秒;
5900 萬條記錄 /3.5GB/ 用戶數(shù)量 40 萬 /132 秒;
11800 萬條記錄 /7GB/ 用戶數(shù)量 80 萬 /327 秒。
分析:
優(yōu)化后,1 倍數(shù)據(jù)量耗時縮減到 2/5;5 倍的數(shù)據(jù)量縮減到 1/5;新測試的 50 倍、100 倍性能也大體隨數(shù)據(jù)量保持了線性。注意到原始數(shù)據(jù)有一些字段用不到,用到的字段也可以通過序號化等手段再簡化,簡化后的文件會小幾倍,從而達到從硬盤減少讀取時間的目的,具體優(yōu)化方式如下↓
思路:
先觀察一下原始數(shù)據(jù):用戶 ID 用從 1 開始的序號替代,除了減少少許存儲空間外,還可以在后續(xù)計算時通過序號快速定位到用戶,減少查找時間。時間和年月日字段信息重復(fù),去掉年月日,長整型的時間字段也可以進一步精簡成相對 2017-01-01 這個開始時間的毫秒數(shù);事前我們知道只有 10 種事件,那事件 ID 和事件名稱可以單獨提取出個維表記錄,這個事實表里只保存序號化的事件 ID(1、2、3…10)就夠了;事件屬性是 JSON 格式,種類不多,那對于某一種事件,可以用序列存儲事件屬性的值,在序列中的位置表示某種屬性,這樣即縮減存儲空間,又能提升查找屬性的效率。
除了上面這些字段值的精簡,我們存儲數(shù)據(jù)的格式棄用文本方式,改變成集算器二進制格式,存儲空間更小,加載速度更快,精簡后的事實表如下:
實現(xiàn):
精簡事實表數(shù)據(jù)之前,要先通過事實表生成用戶表、事件表兩個維表的(genDims.dfx,運行后生成 user.bin 和 event.bin):
A | |
1 | >beginTime=now() |
2 | >fPath="e:/ldsj/demo/" |
3 | =file(fPath+"src-11800.txt").cursor@t() |
4 | =channel(A3) |
5 | =A4.groups(#1:用戶 id) |
6 | =A3.groups(#3:事件 ID,#4: 事件名稱; iterate(~~.import@j().fname()): 屬性名稱) |
7 | =file(fPath+"event.bin").export@b(A6) |
8 | =file(fPath+"user.bin").export@b(A4.result()) |
9 | =interval@s(beginTime,now()) |
提取維表的這段程序,仍然有優(yōu)化的手段體現(xiàn)。提取兩個維表,常規(guī)思維是每遍歷一遍數(shù)據(jù),生成一個維表;從硬盤讀入大量數(shù)據(jù)進行遍歷,讀入慢,但讀入后的計算量卻非常小。針對這種情況,那有什么手段可以在讀入數(shù)據(jù)時,同時用于多種獨立的計算呢,答案就是“管道”,多定義了幾個管道,就多定義了幾種運算。A4 針對 A3 游標定義管道,A5 定義 A4 管道的分組計算,A6 定義另外一個分組計算,A7 導(dǎo)出 A6 的結(jié)果,A8 導(dǎo)出 A4 管道的結(jié)果。最終得到的兩個維表如下:
基于上面兩個維表對事實表進行精簡(toSeq.dfx),6.8G 的文本文件精簡后,得到 1.9G 的二進制文件,縮小了 3.5 倍。
A | B | C | D | |
1 | >beginTime=now() | |||
2 | >fPath="e:/ldsj/demo/" | |||
3 | =file(fPath+"src-11800.txt").cursor@t() | |||
4 | =file(fPath+"event.bin").import@b() | =A4.(事件 ID) | =A4.(屬性名稱 ) | |
5 | =file(fPath+"user.bin").import@b() | =A5.(用戶 ID) | ||
6 | ||||
7 | func | |||
8 | =A7.import@j() | |||
9 | =[] | |||
10 | for B7 | |||
11 | >B9.insert(0,eval("B8."+B10)) | |||
12 | return B9 | |||
13 | ||||
14 | for A3,10000 | |||
15 | =A14.new(C5.pos@b(用戶 ID): 用戶 ID,C4.pos@b( 事件 ID): 事件 ID, 時間: 時間,func(A7, 事件屬性,D4(C4.pos@b( 事件 ID))): 事件屬性 ) | |||
16 | =file(fPath+"src-11800.bin").export@ab(B15) | |||
17 | =interval@s(beginTime,now()) |
這段代碼出現(xiàn)了一個新的知識點,第 7~12 行定義了一個函數(shù)來處理 json 格式的事件屬性,B15 里精簡每一行數(shù)據(jù)時,調(diào)用了這個函數(shù)。B16 把每次精簡好的一萬條記錄追寫入同一個二進制文件。
程序:(4-Reduced.dfx)
在上一次程序的基礎(chǔ)上改造了這么幾個格子:
A3/A4 中的時間相對于 2017-01-01;
A6 事件序列改用序號;
A7 中屬性過濾,用精確匹配值的方式替換以前低效的模糊匹配字符串方式; A10 初始化用戶序列,長度為用戶數(shù),該序列中的位置代表用戶的序號;
C12 用序號方式查找用戶;
E13 用序號方式存儲新用戶:
A | B | C | D | E | |
2 | …… | ||||
3 | >begin=interval@ms(date(2017,1,1),date(2017,1,1)) | ||||
4 | >end=interval@ms(date(2017,1,1),date(2017,3,1)) | ||||
5 | >dateWindow=10*24*60*60*1000 | ||||
6 | >events=[3,4,6,7] | ||||
7 | >filter="if(事件 ID!=4||(事件屬性.len()>0&& 事件屬性 (1)==\"Apple\");true)" | ||||
8 | |||||
9 | /開始執(zhí)行漏斗轉(zhuǎn)換計算程序 | ||||
10 | =to(802060).(null) | ||||
11 | =file(dataFile).cursor@b().select(時間 >=begin&& 時間 <end && events.pos(事件 ID)>0 && ${filter}) | ||||
12 | for A11,10000 | for A12 | >user=A10(B12.用戶 ID) | ||
13 | if user==null | if B12.事件 ID==events(1) | >A10(B12.用戶 ID)=[B12. 用戶 ID,1,[[B12. 時間,1]]] | ||
14 | …… |
結(jié)果:
11800 萬條記錄 /1.93GB/ 用戶數(shù)量 80 萬 /225 秒。
分析:
優(yōu)化后,100 倍數(shù)據(jù)量耗時縮減到上一步的 2/3。除了精簡涉及的查詢字段,我們再看看另一種能有效縮減查詢數(shù)據(jù)量的方法↓
思路:
如何拆分數(shù)據(jù)和查詢特點有關(guān),這個例子中經(jīng)常查詢不定時間段,那按照日期拆分比較合適,按照事件 ID 拆分就沒有意義了。
拆分數(shù)據(jù)的程序(splitData.dfx):
A4 每次取出 10 萬條數(shù)據(jù);B4 循環(huán) 60 天;C6 按照日期查詢到數(shù)據(jù)后,通過 C9 追加到各自日期的文件里。
A | B | C | D | |
1 | =dataFile=file("e:/ldsj/demo/src-11800.bin").cursor@b() | |||
2 | >destFolder="e:/ldsj/demo/dates/" | |||
3 | >oneDay=24*60*60*1000 | |||
4 | for A1,100000 | for 60 | >begin=long(B4-1)*oneDay | |
5 | >end=long((B4))*oneDay | |||
6 | =A4.select(時間 >=begin && 時間 <end) | |||
7 | if (C6 == null) | next | ||
8 | >filename= string(date(long(date(2017,1,1))+begin), "yyyyMMdd")+".bin" | |||
9 | =file(destFolder+fileName).export@ab(C6) |
執(zhí)行后生成 59 天的數(shù)據(jù)文件:
程序:(5-SplitData.dfx)
A2 中把以前被分析的文件定義換成目錄;
A3/A4 的起止日期條件有所變動,以前是查詢?nèi)掌谧侄危F(xiàn)在變成查找日期文件;
A11 把目錄下的日期文件排序,選出要分析的多個日期文件,然后組合成一個游標之后再進行事件過濾就可以了。
A | |
1 | …… |
2 | >fPath="e:/ldsj/demo/dates/" |
3 | >begin="20170201.bin" |
4 | >end="20170205.bin" |
5 | …… |
11 | =directory(fPath+"2017*").sort().select(~>=begin&&~<=end).(file(fPath+~:"UTF-8")).(~.cursor@b()).conjx().select(events.pos(事件 ID)>0 && ${filter}) |
12 | …… |
結(jié)果:
目標數(shù)據(jù)選擇 2017-02-01 至 2017-02-05 這 5 天,全量掃描數(shù)據(jù) 168 秒;只掃描 5 個文件得到相同結(jié)果 7 秒,效果顯著。到目前為止,讀取數(shù)據(jù)和計算都是單線程的,下面我們再試試并行計算↓
程序:(6-mulit-calc.dfx)
增加 B 列,B2 中啟動 4 個線程處理 A12 里加載的 100000 條數(shù)據(jù),C12 中依據(jù)用戶 ID%4 的余數(shù)分成 4 組,分別給 4 個線程進行運算。
A | B | C | |
11 | …… | ||
12 | for A11,100000 | fork to(4) | for A12.select(用戶 ID%4==B12-1) |
13 | …… |
結(jié)果:
11800 萬條 /1.93GB/ 用戶數(shù) 80 萬 /4 線程 / 一次性讀入 10 萬條數(shù)據(jù) /262 秒;
11800 萬條 /1.93GB/ 用戶數(shù) 80 萬 /4 線程 / 一次性讀入 40 萬條數(shù)據(jù) /161 秒;
11800 萬條 /1.93GB/ 用戶數(shù) 80 萬 /4 線程 / 一次性讀入 80 萬條數(shù)據(jù) /233 秒;
11800 萬條 /1.93GB/ 用戶數(shù) 80 萬 /4 線程 / 一次性讀入 400 萬條數(shù)據(jù) /256 秒。
分析:
筆者測試機器是單個機械硬盤,加載數(shù)據(jù)速度是瓶頸,所以對提速不太明顯。但調(diào)整單次加載的數(shù)據(jù)量,還是會有明顯的性能差異。每次處理 40 萬條數(shù)據(jù)時性能最優(yōu)。
預(yù)處理:(splitDataByUserId.dfx)
雖然 4 個線程可以同時讀全量數(shù)據(jù)的同一個文件,但每個線程讀出 3/4 的無用數(shù)據(jù)必然拖慢速度,所以預(yù)先按照用戶 ID%4 拆分一下文件能更快些。C3 查詢出 ID%4 的數(shù)據(jù),C6 把查詢的數(shù)據(jù)存入相應(yīng)的拆分文件。
A | B | C | D | |
1 | =file("e:/ldsj/demo/src-11800.bin").cursor@b() | |||
2 | e:/ldsj/demo/users/ | |||
3 | for A1,100000 | for to(4) | =A3.select(用戶 ID%4==B3-1) | |
4 | if (C3 == null) | next | ||
5 | ="src-11800-"+string(B3)+".bin" | |||
6 | =file(A2+C5).export@ab(C3) |
程序:(6-mulit-read.dfx)
把多線程代碼前移到 A11,每個線程內(nèi)讀取各自的文件進行計算 (B11)。
A | B | C | |
9 | …… | ||
10 | =to(802060).(null) | ||
11 | fork to(4) | =file(fPath+"src-11800-"+string(A11)+".bin").cursor@b().select(時間 >=begin&& 時間 <end && events.pos(事件 ID)>0 && ${filter}) | |
12 | for B11,10000 | …… | |
13 | …… |
結(jié)果:
11800 萬條記錄 /1.93GB/ 用戶數(shù)量 80 萬 /4 線程 /113 秒。
分析:
同樣受限于加載數(shù)據(jù)速度,提速也有限。如果用多臺機器集群,每臺機器處理 1/4 的數(shù)據(jù),因為是多個硬盤并行,速度肯定會有大幅提升,下面我們就看一下如何實現(xiàn)多機并行↓
集算器如何部署集群計算,如何寫集群的主、子程序的知識點不是本文重點關(guān)注的,可以移步相關(guān)的文檔詳細了解:http://doc.raqsoft.com.cn/esproc/tutorial/jqjs.html。
主程序:(6-multi-pc-main.dfx)
A3 中用 callx 調(diào)用子程序 6-multi-pc-sub.dfx,參數(shù)序列 [1,2,3…] 傳入每個子程序控制處理哪一部分數(shù)據(jù);返回的結(jié)果再通過 B6 匯總到一起,結(jié)果存放在 A4 格子里。
A | B | |
1 | >beginTime=now() | |
2 | [127.0.0.1:8281,127.0.0.1:8282] | |
3 | =callx("e:/ldsj/demo/6-multi-pc-sub.dfx",to(2),"e:/ldsj/demo/users/";A2) | |
4 | ||
5 | for A3 | |
6 | >A4=if(A4==null,A5,A4++A5) | |
7 | =interval@s(beginTime,now()) |
A3 得到結(jié)果序列:
A4 匯總出最終結(jié)果:
節(jié)點機子程序:(6-multi-pc-sub.dfx)
相比較上一步單機多線程加載數(shù)據(jù)的程序,去掉 A11 的多線程 fork to(4);節(jié)點機計算哪個拆分文件是通過 taskSeq 參數(shù)由主程序傳過來的(B11);A22 把 A20 里的結(jié)果返回給主程序。
A | B | C | |
9 | …… | ||
10 | =to(802060).(null) | ||
11 | =file(fPath+"src-11800-"+string(taskSeq)+".bin").cursor@b().select(時間 >=begin&& 時間 <end && events.pos(事件 ID)>0 && ${filter}) | ||
12 | for B11,10000 | …… | |
13 | …… | ||
22 | return A20 |
結(jié)果:
11800 萬條記錄 /1.93GB/ 用戶數(shù)量 80 萬 / 單節(jié)點機處理四分之一數(shù)據(jù) /38 秒。主程序匯總的時間很短忽略不計,也就是 4 個 PC 的四塊硬盤并行加載數(shù)據(jù)時,能把速度提升到 38 秒。
程序和測試數(shù)據(jù)在百度網(wǎng)盤下載 。安裝好集算器,修改下程序里的文件路徑,就可以運行看效果了。
看到上面這么多的優(yōu)化細節(jié),估計有人質(zhì)疑,這么費力的把這事做到極致,是不是吹毛求疵了?數(shù)據(jù)庫應(yīng)該是內(nèi)置了一些自動的優(yōu)化算法,目前已有共識的是尤其 ORACLE 在這方面已經(jīng)做的很細致,這些細節(jié)根本不需要用戶操心。確實,自動性能優(yōu)化的重要意義是肯定的,但近幾年隨著數(shù)據(jù)環(huán)境的復(fù)雜化,數(shù)據(jù)量的劇增,更精細的控制數(shù)據(jù)的能力也就有了越來越多的應(yīng)用場景,雖然會增加學(xué)習(xí)成本,但也會帶來更高的數(shù)據(jù)收益。而且這個學(xué)習(xí)成本除了解決性能問題外,還能更好地解決根本上的描述復(fù)雜計算、整理數(shù)據(jù)方面的業(yè)務(wù)需求,更何況這類問題是無法自動化的,因為是“決策要做什么”變復(fù)雜了,因此只能提供更方便的編程語言提高描述效率,正視問題。計算機再智能,也不能替代人類做決策。自動和手動兩種方式不是對立,而是互補的關(guān)系!
上面這些優(yōu)化的思路是我們程序員能預(yù)先想到的,同時也大概能根據(jù)計算任務(wù)特點選擇效果顯著的優(yōu)化方式。但我要說的是計算機系統(tǒng)太復(fù)雜了:特點迥異的計算需求、不穩(wěn)定的硬盤讀寫速度、不穩(wěn)定的網(wǎng)絡(luò)速度、無法估量的 CPU 具體計算量!所以實際業(yè)務(wù)中我們還需要依靠經(jīng)驗根據(jù)實際優(yōu)化的效果來選擇優(yōu)化方法。
SPL 出現(xiàn)以前,因為優(yōu)化方式的實現(xiàn)和維護都比較困難,因此試驗動作就難以密集進行,優(yōu)化成果不多也就是自然的了;同時因為缺乏密集“倒騰”數(shù)據(jù)的鍛煉,優(yōu)化經(jīng)驗的積累也不容易,這也從另一個角度驗證了高級數(shù)據(jù)分析師人才昂貴的現(xiàn)狀。使用高效工具的第一批人,永遠是獲益最大的那一群人,第一批用弓箭的,第一批用槍的,第一批用坦克的,第一個用×××的……而你就是第一批用 SPL 的程序員。程序員的龐大隊伍里分化出一支專業(yè)搞數(shù)據(jù)處理、分析的數(shù)據(jù)程序員,形成一個有獨立技能的職業(yè),這是必然的趨勢。您的職業(yè)規(guī)劃,方向選擇也要盡早有個打算,才有占領(lǐng)某一高地的可能。
最后還要說一句,目前這個結(jié)果仍然還有優(yōu)化余地。如果再將數(shù)據(jù)壓縮存儲,還可以進一步減少硬盤訪問時間,而數(shù)據(jù)經(jīng)過一定的排序并采用列式存儲后確實還可以再壓縮。另外,這里的集群運算拆分成了 4 個子任務(wù),而即使配置相同的機器,也可能運算性能不同,這時候就會發(fā)生運算快的要等運算慢的,最終完成時間是以計算最慢的那臺機器為準,如果我們能把任務(wù)拆得更細一些,就可以做到更平均的效率,從而進一步提高計算速度。這些內(nèi)容,我們將在后面的文章繼續(xù)講述。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。