10行代碼解決漏斗轉(zhuǎn)換計算之性能優(yōu)化

大話數(shù)據(jù)計算性能優(yōu)化

大數(shù)據(jù)分析的性能優(yōu)化,說道底,就優(yōu)化一個事情:針對確定的一個計算任務(wù)(數(shù)據(jù)確定,結(jié)果確定),以最經(jīng)濟的方案得到結(jié)果。

創(chuàng)新互聯(lián)服務(wù)項目包括平昌網(wǎng)站建設(shè)、平昌網(wǎng)站制作、平昌網(wǎng)頁制作以及平昌網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,平昌網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到平昌省份的部分城市,未來相信會繼續(xù)擴大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!

這個最經(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)化效果。

1、未做任何優(yōu)化,直接開工

數(shù)據(jù):

10 行代碼解決漏斗轉(zhuǎn)換計算之性能優(yōu)化

程序:(附件中的 1-First.dfx,也附帶了測試數(shù)據(jù)文件,可在集算器里直接執(zhí)行)

       漏斗轉(zhuǎn)換計算核心代碼的邏輯細(xì)節(jié)在上一篇中詳細(xì)介紹過,這里就不再贅述。

結(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、按用戶 ID 順序插入用戶列表,用二分法查找用戶。

程序:(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 耗時還比較嚴(yán)重,根據(jù)經(jīng)驗可以繼續(xù)優(yōu)化↓

3、批量讀入游標(biāo)數(shù)據(jù)

程序:(3-BatchReadFromCursor.dfx)

       12~17 行整體剪切后,向右移一個格子之后,在 A12 增加一個批量加載游標(biāo)數(shù)據(jù)的循環(huán),表示 A11 中的游標(biāo)每次取 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)化方式如下↓

4、精簡數(shù)據(jù)

思路:

        先觀察一下原始數(shù)據(jù):用戶 ID 用從 1  開始的序號替代,除了減少少許存儲空間外,還可以在后續(xù)計算時通過序號快速定位到用戶,減少查找時間。時間和年月日字段信息重復(fù),去掉年月日,長整型的時間字段也可以進一步精簡成相對  2017-01-01 這個開始時間的毫秒數(shù);事前我們知道只有 10 種事件,那事件 ID  和事件名稱可以單獨提取出個維表記錄,這個事實表里只保存序號化的事件 ID(1、2、3…10)就夠了;事件屬性是 JSON  格式,種類不多,那對于某一種事件,可以用序列存儲事件屬性的值,在序列中的位置表示某種屬性,這樣即縮減存儲空間,又能提升查找屬性的效率。

10 行代碼解決漏斗轉(zhuǎn)換計算之性能優(yōu)化

       除了上面這些字段值的精簡,我們存儲數(shù)據(jù)的格式棄用文本方式,改變成集算器二進制格式,存儲空間更小,加載速度更快,精簡后的事實表如下:

10 行代碼解決漏斗轉(zhuǎn)換計算之性能優(yōu)化

實現(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(~~&#5.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 游標(biāo)定義管道,A5 定義 A4 管道的分組計算,A6 定義另外一個分組計算,A7 導(dǎo)出 A6 的結(jié)果,A8 導(dǎo)出 A4  管道的結(jié)果。最終得到的兩個維表如下:

10 行代碼解決漏斗轉(zhuǎn)換計算之性能優(yōu)化

10 行代碼解決漏斗轉(zhuǎn)換計算之性能優(yōu)化

       基于上面兩個維表對事實表進行精簡(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ù)量的方法↓

5、把數(shù)據(jù)預(yù)先拆分存儲,計算的時候只加載涉及到的數(shù)據(jù)

思路:

       如何拆分?jǐn)?shù)據(jù)和查詢特點有關(guān),這個例子中經(jīng)常查詢不定時間段,那按照日期拆分比較合適,按照事件 ID 拆分就沒有意義了。

拆分?jǐn)?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ù)文件:

10 行代碼解決漏斗轉(zhuǎn)換計算之性能優(yōu)化

程序:(5-SplitData.dfx)

       A2 中把以前被分析的文件定義換成目錄;

       A3/A4 的起止日期條件有所變動,以前是查詢?nèi)掌谧侄?,現(xiàn)在變成查找日期文件;

       A11 把目錄下的日期文件排序,選出要分析的多個日期文件,然后組合成一個游標(biāo)之后再進行事件過濾就可以了。

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é)果:

       目標(biāo)數(shù)據(jù)選擇 2017-02-01 至 2017-02-05 這 5 天,全量掃描數(shù)據(jù) 168 秒;只掃描 5 個文件得到相同結(jié)果 7 秒,效果顯著。到目前為止,讀取數(shù)據(jù)和計算都是單線程的,下面我們再試試并行計算↓

6、并行計算

單線程加載數(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)。

多線程加載數(shù)據(jù)

預(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)的文檔詳細(xì)了解: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…] 傳入每個子程序控制處理哪一部分?jǐn)?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é)果序列:

10 行代碼解決漏斗轉(zhuǎn)換計算之性能優(yōu)化

       A4 匯總出最終結(jié)果:

10 行代碼解決漏斗轉(zhuǎn)換計算之性能優(yōu)化

節(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)盤下載。安裝好集算器,修改下程序里的文件路徑,就可以運行看效果了。

結(jié)束語 - 前瞻

        看到上面這么多的優(yōu)化細(xì)節(jié),估計有人質(zhì)疑,這么費力的把這事做到極致,是不是吹毛求疵了?數(shù)據(jù)庫應(yīng)該是內(nèi)置了一些自動的優(yōu)化算法,目前已有共識的是尤其  ORACLE  在這方面已經(jīng)做的很細(xì)致,這些細(xì)節(jié)根本不需要用戶操心。確實,自動性能優(yōu)化的重要意義是肯定的,但近幾年隨著數(shù)據(jù)環(huán)境的復(fù)雜化,數(shù)據(jù)量的劇增,更精細(xì)的控制數(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ā)生運算快的要等運算慢的,最終完成時間是以計算最慢的那臺機器為準(zhǔn),如果我們能把任務(wù)拆得更細(xì)一些,就可以做到更平均的效率,從而進一步提高計算速度。這些內(nèi)容,我們將在后面的文章繼續(xù)講述。

文章題目:10行代碼解決漏斗轉(zhuǎn)換計算之性能優(yōu)化
網(wǎng)站URL:http://www.muchs.cn/article12/ghjgdc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站設(shè)計、網(wǎng)站維護、手機網(wǎng)站建設(shè)網(wǎng)站導(dǎo)航、軟件開發(fā)、用戶體驗

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站優(yōu)化排名