SQL作為目前最常用的數(shù)據(jù)處理語(yǔ)言,廣泛應(yīng)用于查詢、跑批等場(chǎng)景。當(dāng)數(shù)據(jù)量較大時(shí),使用SQL(以及存儲(chǔ)過(guò)程)經(jīng)常會(huì)發(fā)生跑得很慢的情況,這就要去優(yōu)化SQL。優(yōu)化SQL有一些特定的套路,通常先要查看執(zhí)行計(jì)劃來(lái)定位SQL慢的原因,然后針對(duì)性改寫來(lái)優(yōu)化SQL,比如對(duì)于連續(xù)數(shù)值判斷可以用來(lái)替代in,語(yǔ)句指明字段名稱存儲(chǔ)過(guò)程執(zhí)行動(dòng)態(tài)查詢,用union all替代union,把改寫成join等。當(dāng)然還有一些工程上的優(yōu)化手段,如建立索引,使用臨時(shí)表/匯總表等,優(yōu)化的方法有很多,相信各位DBA都不會(huì)陌生。
但遺憾的是,仍然有相當(dāng)多情況無(wú)論怎樣優(yōu)化都不可能跑得更快。這里做 SQL 性能優(yōu)化真是讓人干瞪眼 介紹了一些,并做了相應(yīng)的技術(shù)分析。由于其理論基礎(chǔ)關(guān)系代數(shù)的局限,SQL缺乏離散性和有序集合等特性的支持使得SQL在表達(dá)某些高性能算法時(shí)異常困難,甚至完全寫不出來(lái),只能采用比較笨的低性能算法,眼睜睜地看著硬件資源被白白浪費(fèi)。在 寫著簡(jiǎn)單跑得又快的數(shù)據(jù)庫(kù)語(yǔ)言 SPL 中有對(duì)SQL理論基礎(chǔ)缺陷的通俗解釋。也就是說(shuō),SQL的慢是理論性的,這種問(wèn)題僅僅由數(shù)據(jù)庫(kù)在工程層面優(yōu)化只能局部改善(確實(shí)有不少商業(yè)數(shù)據(jù)庫(kù)能夠自動(dòng)識(shí)別某些SQL并轉(zhuǎn)換成高性能算法),而不能根本地解決問(wèn)題(情況復(fù)雜時(shí)數(shù)據(jù)庫(kù)優(yōu)化引擎都會(huì)”暈”掉,只能按SQL的書寫邏輯執(zhí)行成低性能算法)。理論性的缺陷當(dāng)然也不能寄希望于更換數(shù)據(jù)庫(kù)而得到解決,只要還是用SQL,即使采用分布式數(shù)據(jù)庫(kù)、內(nèi)存數(shù)據(jù)庫(kù)也還是這種情況,在消耗更大成本的資源后當(dāng)然也能有一定的性能提升,但和硬件本應(yīng)能夠達(dá)到的性能仍然有巨大的差距。
那還能怎么辦?
那就不能再用SQL!也就不能再用關(guān)系數(shù)據(jù)庫(kù)了。
那用什么?
SQL描述不了這些高性能算法,用Java,C++行嗎?
沒(méi)問(wèn)題!從理論上講,Java、C++什么算法都能實(shí)現(xiàn),而且因?yàn)榭梢钥刂朴?jì)算機(jī)底層的動(dòng)作,這類代碼通常可以跑出很好的速度(只要程序員能力不是太差)。
不過(guò),不要高興得太早,雖然都寫得出來(lái),但由于這些開發(fā)語(yǔ)言過(guò)于原生,本身沒(méi)有提供什么面向數(shù)據(jù)處理的高性能計(jì)算類庫(kù),想實(shí)現(xiàn)這些算法就必須從頭實(shí)現(xiàn),而這恐怕要累死。以哈希關(guān)聯(lián)為例,Java實(shí)現(xiàn)至少要寫幾百行代碼,不僅要設(shè)計(jì)合適的哈希函數(shù),還要解決可能出現(xiàn)的哈希沖突,這一套下來(lái)的工程量可不小;還有在Java中進(jìn)行多線程編程也并非易事,但并行計(jì)算又是提升計(jì)算性能的有效手段。類似的,涉及結(jié)構(gòu)化數(shù)據(jù)計(jì)算的算法還有很多,這些都自己來(lái)做的復(fù)雜度可想而知。如果一個(gè)計(jì)算的實(shí)現(xiàn)過(guò)于復(fù)雜,其開發(fā)代價(jià)已經(jīng)遠(yuǎn)遠(yuǎn)超過(guò)性能優(yōu)化本身,那也就沒(méi)有優(yōu)化的意義了。
也面臨類似的問(wèn)題,雖然在結(jié)構(gòu)化數(shù)據(jù)計(jì)算類庫(kù)方面要比Java豐富得多,但并沒(méi)有提供必要的高性能算法庫(kù)和存儲(chǔ)方案,比如沒(méi)有提供為大數(shù)據(jù)服務(wù)的游標(biāo)類型及相關(guān)運(yùn)算,也沒(méi)提供有效的并行機(jī)制。想要實(shí)施那些高性能算法也只能自己開發(fā),但作為解釋執(zhí)行語(yǔ)言,本身運(yùn)行效率不高,在此基礎(chǔ)上再開發(fā)的算法也往往達(dá)不到高性能要求。同樣,Scala也缺乏足夠的高性能計(jì)算類庫(kù),自己編寫的算法同樣復(fù)雜度相當(dāng)高,對(duì)于不熟悉這些算法的程序員來(lái)講,從頭實(shí)現(xiàn)的代碼的運(yùn)行效率往往還不如努力優(yōu)化后商用數(shù)據(jù)庫(kù)SQL的速度。
那就只能忍受SQL的慢了嗎?
還可以用SPL!
SPL和高性能
開源SPL( ),一個(gè)專門面向結(jié)構(gòu)化數(shù)據(jù)處理的程序語(yǔ)言。使用SPL可以讓原本SQL跑得慢的計(jì)算變快。
為什么SPL能跑得快?是擁有了什么改變硬件性能的黑科技嗎?
那倒沒(méi)有。軟件改變不了硬件的計(jì)算性能,SPL也一樣。簡(jiǎn)單來(lái)說(shuō),SPL快就是上面說(shuō)的,要使用更高性能的算法。SPL中提供了大量基礎(chǔ)的高性能算法類庫(kù),基于這些算法庫(kù)實(shí)現(xiàn)的代碼可以有效減少計(jì)算量,而我們做計(jì)算就是組合運(yùn)用這些算法,每種計(jì)算都快一些,那整體上就會(huì)快很多,從而達(dá)到提升計(jì)算性能的目的。
SPL設(shè)計(jì)的這些高性能算法,像遍歷復(fù)用、有序歸并、外鍵預(yù)關(guān)聯(lián)、標(biāo)簽位維度、并行計(jì)算等,都已經(jīng)封裝好。這其中有很多算法都是SPL獨(dú)創(chuàng)的,在業(yè)內(nèi)也是首次出現(xiàn)。
基于這些封裝好的算法庫(kù),再寫程序會(huì)就很方便,拿來(lái)直接用而不需要從頭自己開發(fā),不僅性能高,開發(fā)也快。從這個(gè)角度來(lái)看,跑得快和寫著簡(jiǎn)單其實(shí)是一回事,就是能高效率地編寫高性能算法。反觀Java、C++、、Scala由于缺少這些算法庫(kù),想要實(shí)現(xiàn)高性能也就很難了。
SPL采用和SQL不同的觀念看待同一個(gè)計(jì)算任務(wù),繼而可以采用不同(更低)復(fù)雜度的計(jì)算方法。
在實(shí)戰(zhàn)中,SPL目前已經(jīng)做過(guò)不少性能優(yōu)化案例,少則提速數(shù)倍,多則數(shù)十倍,極端情況還有提速上千倍的,提速一個(gè)數(shù)量級(jí)基本上是常態(tài)。
比如在優(yōu)化某保險(xiǎn)公司車險(xiǎn)保單跑批的案例( 開源 SPL 優(yōu)化保險(xiǎn)公司跑批優(yōu)從 2 小時(shí)到 17 分鐘 )中,使用SPL將計(jì)算時(shí)間從2小時(shí)縮短到17分鐘,同時(shí)代碼量減少了2/3。這里使用了SPL特有的遍歷復(fù)用技術(shù),可以在對(duì)大數(shù)據(jù)的一次遍歷過(guò)程中實(shí)現(xiàn)多種運(yùn)算,有效地減少外存訪問(wèn)量。這個(gè)案例涉及對(duì)一個(gè)大表進(jìn)行三次關(guān)聯(lián)和匯總的運(yùn)算,使用SQL要將大表遍歷三次,而使用SPL只需要遍歷一次,并在關(guān)聯(lián)運(yùn)算上也采用了不同的方法,因此獲得了巨大的性能提升。
還有在 開源 SPL 將銀行手機(jī)賬戶查詢的預(yù)先關(guān)聯(lián)變成實(shí)時(shí)關(guān)聯(lián) 的案例中,使用SPL將原本只能預(yù)關(guān)聯(lián)的手機(jī)賬戶查詢變成實(shí)時(shí)關(guān)聯(lián),同時(shí)服務(wù)器數(shù)量從6臺(tái)降為1臺(tái)。這里充分利用了SPL的有序存儲(chǔ)機(jī)制,一次性讀取整個(gè)賬戶數(shù)據(jù)時(shí)可以有效減少硬盤時(shí)間(物理存儲(chǔ)連續(xù)),再借助區(qū)分維表和事實(shí)表的外鍵實(shí)時(shí)關(guān)聯(lián)技術(shù)使用單機(jī)就能完成實(shí)時(shí)關(guān)聯(lián)查詢,性能提升明顯,硬件需求也降低了許多。
這里還整理了一些常見(jiàn)的業(yè)務(wù)場(chǎng)景,可以利用SPL的算法庫(kù)來(lái)實(shí)現(xiàn)的高性能:
進(jìn)一步討論
說(shuō)到這里你可能會(huì)想,那是不是學(xué)會(huì)SPL語(yǔ)法就能把計(jì)算跑得快了?
也沒(méi)這么簡(jiǎn)單!
使用SPL可以獲得更高性能不是因?yàn)镾PL語(yǔ)法,SPL語(yǔ)法雖然有些特色,但并不是跑得快的根本原因。最關(guān)鍵的是 掌握和運(yùn)用高性能算法。
實(shí)現(xiàn)性能優(yōu)化有兩步:第一步設(shè)計(jì)出低復(fù)雜的計(jì)算方案,第二步用足夠低的成本實(shí)現(xiàn)它。其中更關(guān)鍵的是第一步,這需要由有一定經(jīng)驗(yàn)和知識(shí)儲(chǔ)備的程序員來(lái)做(即掌握和運(yùn)用高性能算法),第二步才是用SPL來(lái)做。換句話說(shuō),SPL并不負(fù)責(zé)設(shè)計(jì)解決問(wèn)題的方法,而只是負(fù)責(zé)讓解法更容易實(shí)現(xiàn)出來(lái)。
SPL語(yǔ)法很簡(jiǎn)單,比 Java 容易得多,兩小時(shí)就能基本上手,兩三周就能比較熟練了。但算法卻沒(méi)那么簡(jiǎn)單,需要認(rèn)真學(xué)習(xí)反復(fù)練習(xí)才能掌握。反過(guò)來(lái),只要掌握了算法,用什么語(yǔ)法就是個(gè)相對(duì)次要的問(wèn)題了(當(dāng)然用 SQL 這種太粗線條的語(yǔ)言還是不行)。這就像給病人看病,找出病理原因后,能分析出什么成分的藥能管用。無(wú)論直接購(gòu)買成藥(使用封裝過(guò)的 SPL),還是上山采藥(使用 Java/C++ 硬寫),都可以治好病,無(wú)非就是麻煩程度和支付成本不同。
因?yàn)閷?shí)際中很少使用,有不少應(yīng)用程序員工作幾年后都把大學(xué)時(shí)代學(xué)過(guò)的數(shù)據(jù)結(jié)構(gòu)和算法課程內(nèi)容忘了,而不理解這些基礎(chǔ)算法知識(shí)時(shí)也就沒(méi)辦法設(shè)計(jì)出高性能算法方案。為此,SPL設(shè)置了專門的高性能專題,不僅涵蓋高性能算法與優(yōu)化技巧,還有性能優(yōu)化課程與性能圖書來(lái)授人以漁。
和算法密切相關(guān)的,高性能計(jì)算還有一個(gè)關(guān)鍵點(diǎn)是數(shù)據(jù)存儲(chǔ),高性能計(jì)算離不開合理的數(shù)據(jù)存儲(chǔ)方式。使用SPL實(shí)施高性能計(jì)算時(shí)也不能再基于數(shù)據(jù)庫(kù)來(lái)做,需要 將數(shù)據(jù)從數(shù)據(jù)庫(kù)里搬出來(lái)重新組織。
為什么呢?
慢的數(shù)據(jù)計(jì)算任務(wù)可以分為計(jì)算密集型和數(shù)據(jù)密集型兩大類。單純的計(jì)算密集型任務(wù)涉及的數(shù)據(jù)量不大而只是計(jì)算量很大,計(jì)算量大并不是由于數(shù)據(jù)量大造成的,這樣不用改變存儲(chǔ)方式,只要實(shí)施了好的計(jì)算方法也能大幅提升性能,也就是說(shuō),可以繼續(xù)在原有的存儲(chǔ)方式(比如數(shù)據(jù)庫(kù))上使用SPL來(lái)優(yōu)化性能。而數(shù)據(jù)密集型任務(wù)涉及的計(jì)算量也很大,但計(jì)算量大主要是由數(shù)據(jù)量大造成的,這時(shí)候如果不改變存儲(chǔ)方式,數(shù)據(jù)讀取時(shí)間很可能會(huì)很長(zhǎng),即使能把計(jì)算時(shí)間優(yōu)化到0,整體運(yùn)算時(shí)間也不能得到有效的優(yōu)化。
遺憾的是,我們面臨的計(jì)算慢的場(chǎng)景絕大部分屬于數(shù)據(jù)密集型計(jì)算。如果數(shù)據(jù)還存在數(shù)據(jù)庫(kù)中,而數(shù)據(jù)庫(kù)取數(shù)接口(如JDBC)通常又非常慢,將數(shù)據(jù)讀出就要消耗很長(zhǎng)時(shí)間(IO效率很低),經(jīng)常遠(yuǎn)遠(yuǎn)超過(guò)后續(xù)SPL計(jì)算的時(shí)間,這也就不可能達(dá)到優(yōu)化效果了。而且,SPL中有相當(dāng)多的算法也對(duì)存儲(chǔ)組織有要求,比如單邊分堆算法就要求有序的存儲(chǔ)方式,而常規(guī)關(guān)系數(shù)據(jù)庫(kù)無(wú)法滿足這個(gè)前提,這些算法也無(wú)法實(shí)施了。
為了解決這個(gè)問(wèn)題,SPL提供了自有的存儲(chǔ)機(jī)制,直接采用文件系統(tǒng),將數(shù)據(jù)從數(shù)據(jù)庫(kù)導(dǎo)出到特定格式的文件中,不僅可以獲得更高的IO存取效率以及文件系統(tǒng)靈活的管理能力,還可以充分利用自有格式的列存、有序、壓縮、并行分段等數(shù)據(jù)存儲(chǔ)優(yōu)勢(shì),從而高效地發(fā)揮高性能算法效力。
使用文件存儲(chǔ)數(shù)據(jù)還可以有效減少數(shù)據(jù)入庫(kù)的時(shí)間,進(jìn)一步提升計(jì)算性能。有些計(jì)算場(chǎng)景不僅要從數(shù)據(jù)源讀,還要將計(jì)算結(jié)果落地,存入數(shù)據(jù)庫(kù)以方便后續(xù)計(jì)算使用。像ETL就是典型的讀寫并存的計(jì)算,還有某些大數(shù)據(jù)計(jì)算或復(fù)雜計(jì)算需要將中間結(jié)果暫存存儲(chǔ)過(guò)程執(zhí)行動(dòng)態(tài)查詢,后續(xù)計(jì)算還需要再使用的情況。我們知道,數(shù)據(jù)庫(kù)寫入是非常慢的動(dòng)作,伴隨寫入的計(jì)算場(chǎng)景性能自然低下。這時(shí)就可以將原本需要入庫(kù)的數(shù)據(jù)存儲(chǔ)在文件中(雖然這是工程方面的優(yōu)勢(shì),但仍可獲得接近數(shù)量級(jí)的讀寫性能提升),再利用SPL的文件計(jì)算能力直接計(jì)算,從而實(shí)現(xiàn)高性能。
如果把所有的數(shù)據(jù)移出數(shù)據(jù)庫(kù),難道就不可能完成實(shí)時(shí)的數(shù)據(jù)計(jì)算嗎?畢竟,數(shù)據(jù)是不斷產(chǎn)生的。
[En]
If you move all the data out of the , is it to the real-time data ? After all, data are being .
沒(méi)有問(wèn)題。
對(duì)于全量T+0實(shí)時(shí)查詢,SPL提供了多源混合計(jì)算的能力以滿足這類場(chǎng)景。冷數(shù)據(jù)量大且不再變化使用SPL的高性能文件存儲(chǔ),這樣可以獲得更高地計(jì)算性能;熱數(shù)據(jù)量小仍然存放在原有數(shù)據(jù)源中,SPL直接讀取計(jì)算(支持多樣性數(shù)據(jù)源),由于熱數(shù)據(jù)量并不大,直接基于生產(chǎn)數(shù)據(jù)源查詢也不會(huì)對(duì)其造成太大影響,訪問(wèn)時(shí)間也不會(huì)太長(zhǎng)。冷熱數(shù)據(jù)混合計(jì)算,就可以獲得針對(duì)全量數(shù)據(jù)的T+0實(shí)時(shí)查詢。我們只要定期將變冷的數(shù)據(jù)固化到SPL的高性能存儲(chǔ)中,原數(shù)據(jù)源只需要保持少量近期新產(chǎn)生的熱數(shù)據(jù)即可。整體架構(gòu)如下:
如何開始
從前面的分析可以知道,完成性能優(yōu)化任務(wù)必須熟悉高性能算法和存儲(chǔ)機(jī)制,但從上面的課程圖書也可以看出來(lái),這些內(nèi)容并不少,都要融會(huì)貫通也不是很容易的事。特別是很多程序員都習(xí)慣了SQL的思維方式,很難跳出這個(gè)窠臼。面對(duì)一個(gè)性能優(yōu)化任務(wù),即使有了開源SPL這樣的有利武器,也常常有點(diǎn)無(wú)從下手。打個(gè)比方,一個(gè)趕馬車的高手想跑得更快時(shí),會(huì)習(xí)慣于尋找韁繩和鞭子,而對(duì)于初次見(jiàn)到的汽車上的方向盤和油門卻會(huì)感到一頭霧水。
為此, SPL團(tuán)隊(duì)也提供相應(yīng)的咨詢服務(wù):你可以把遇到的性能問(wèn)題拿過(guò)來(lái)與我們一起討論和設(shè)計(jì)優(yōu)化方案,必要的時(shí)候還可以進(jìn)行POC。
我們通常關(guān)心這樣一些必要的問(wèn)題信息:業(yè)務(wù)場(chǎng)景、面臨痛點(diǎn)、當(dāng)前計(jì)算的數(shù)據(jù)量和并發(fā)量以及響應(yīng)時(shí)間,如果還能提供SQL腳本、表結(jié)構(gòu)和測(cè)試數(shù)據(jù)就更好了。留個(gè)郵箱方便交流:。
相信我們,從不失手!
經(jīng)歷過(guò)一兩個(gè)案子,程序員們就會(huì)熟悉SPL的思維方式(理解了方向盤和油門),以后再自己做性能優(yōu)化就不是問(wèn)題了。
世界上的武術(shù)只能快而不破,但只有掌握了速度的精髓和方法,才能立于不敗之地。難道你不覺(jué)得?
[En]
The arts in the world can only be fast and , but only by the and of speed can we be . Don’t you think?
SPL資料
:
:
Title: SQL(及存儲(chǔ)過(guò)程)跑得太慢怎么辦?