去“O”?存儲(chǔ)過程還值得我們用么
?今天南方陰雨綿綿,我在回京的高鐵上。回想到年前工作分享時(shí),提到了項(xiàng)目中對(duì)存儲(chǔ)過程的使用,同事們對(duì)是否使用存儲(chǔ)過程還是有很多看法??偨Y(jié)下來主要有對(duì)接難、可維護(hù)性差、數(shù)據(jù)庫遷移時(shí)需重構(gòu)等方面問題,總之就是不要用,拆解回應(yīng)用(代碼)層。
??其實(shí)這些問題在使用之前我都了解,去“O”勢(shì)在必行嘛~在《阿里巴巴JAVA開發(fā)手冊(cè)》(下面我統(tǒng)稱為手冊(cè))中也有提到,堅(jiān)持使用倒不是為了顯擺,而是對(duì)存儲(chǔ)過程到底要不要用、為何而用我還有些想不通。我對(duì)待技術(shù)選型,堅(jiān)持以實(shí)際業(yè)務(wù)場景為依據(jù),不能一刀切,在我們項(xiàng)目中存在15%左右的業(yè)務(wù)邏輯有強(qiáng)相關(guān)屬性,有一定并發(fā)度,這里引入存儲(chǔ)過程我認(rèn)為并不失禮。如果揉在一起,在實(shí)際應(yīng)用中連接次數(shù)會(huì)明顯增高,一定程度上影響效率,當(dāng)然也避免了同事們不想看到的問題。
??作為技術(shù)人,我不愿看到因?yàn)閤xx問題而直接拒接xxx技術(shù)這種情況,該篇文章是網(wǎng)上多方技術(shù)人針對(duì)存儲(chǔ)過程到底是值不值得用這個(gè)問題的一些見解,我挑選了一些比較高贊或有效的回答,做個(gè)分享,能耐心看完的同學(xué),我相信你會(huì)留下自己的看法。
靈劍
??存儲(chǔ)過程沒有版本控制,版本迭代的時(shí)候要更新很麻煩。存儲(chǔ)過程如果和外部程序結(jié)合起來用,更新的時(shí)候很難無感升級(jí),可能需要停服。存儲(chǔ)過程不利于將來分庫分表。存儲(chǔ)過程的功能不一定夠強(qiáng)大,業(yè)務(wù)擴(kuò)展之后可能會(huì)發(fā)現(xiàn)無法繼續(xù)用存儲(chǔ)過程實(shí)現(xiàn)了。存儲(chǔ)過程可能無法和許多中間件、ORM庫一起使用。某些特殊的兼容MySQL的實(shí)現(xiàn)可能根本就不支持存儲(chǔ)過程,那就更不用說了。
??這也不絕對(duì),在微軟的時(shí)候就有項(xiàng)目是反過來的,所有業(yè)務(wù)都需要用存儲(chǔ)過程寫在SQLServer里面,查詢?nèi)珜懗梢晥D,業(yè)務(wù)代碼只允許使用視圖和存儲(chǔ)過程,只要SELECT和EXECUTE權(quán)限就夠了;修改業(yè)務(wù)只需要登服務(wù)器改存儲(chǔ)過程。這屬于思路不同。
精致的噴火住
??10年前剛剛畢業(yè),上班的時(shí)候,視圖、存儲(chǔ)過程、外鍵,能用的都用。?!,F(xiàn)在數(shù)據(jù)庫只存數(shù)據(jù),其他啥也不干。
不悟正業(yè)
??這是針對(duì)互聯(lián)網(wǎng)企業(yè)的規(guī)則。單次請(qǐng)求涉及數(shù)據(jù)少,數(shù)據(jù)關(guān)系簡單,但是更新頻率高;
??工程的迭代速率高,數(shù)據(jù)關(guān)系隨時(shí)可能擴(kuò)展修改。
??ERP開發(fā)面對(duì)的情況是經(jīng)常要大批量的處理數(shù)據(jù),表都很大,表關(guān)系也復(fù)雜,十幾個(gè)表關(guān)聯(lián)不是什么大不了的情況。數(shù)據(jù)處理流程長,不用存儲(chǔ)過程只會(huì)讓事情更加復(fù)雜。
??ERP中對(duì)數(shù)據(jù)庫請(qǐng)求量相比互聯(lián)網(wǎng)企業(yè)來說是非常低的,相對(duì)不用太關(guān)心數(shù)據(jù)庫壓力問題,這種時(shí)候把一些操作放到數(shù)據(jù)存儲(chǔ)過程里可以兼顧效率和開發(fā)成本。
dl yin
??存儲(chǔ)過程依賴數(shù)據(jù)庫,特別是Oracle和sqlserver的性能,阿里巴巴的數(shù)據(jù)庫是分布式存儲(chǔ),用存儲(chǔ)過程會(huì)出大事的。
有銘
??因?yàn)榛ヂ?lián)網(wǎng)行業(yè)的劇烈變化特性,存儲(chǔ)過程是無法適應(yīng)這種天天改的需求的。就算你維持了一個(gè)和代碼開發(fā)組等量齊觀的dba組,存儲(chǔ)過程的修改過程和代價(jià)還是比代碼高多了。存儲(chǔ)過程最適合的是業(yè)務(wù)比較成熟,基本無變動(dòng),而對(duì)性能和一致性要求高的場合。對(duì)互聯(lián)網(wǎng)這種恨不得一天變3次的玩法,不適應(yīng)。
Rex M
??任何技術(shù)都要分使用場景,阿里這種互聯(lián)網(wǎng)高并發(fā)的場景,很多數(shù)據(jù)都是分庫分表的,而且要求高度可擴(kuò)展,原則是對(duì)db的保護(hù)做到最大化,能減少db壓力的就減少db壓力,盡量把運(yùn)算邏輯拉到代碼里面。存儲(chǔ)過程的優(yōu)點(diǎn)在于封裝性好,直接讓db進(jìn)行運(yùn)算,但是缺點(diǎn)在于難以維護(hù),而且大大增大db壓力。所以開發(fā)過程中禁止使用存儲(chǔ)過程也是阿里多年經(jīng)驗(yàn)積累出來的。
馮若航
??因?yàn)檫@里數(shù)據(jù)庫特指MySQL。這種一刀切的回答當(dāng)然必須得考量上下文:一來MySQL的存儲(chǔ)過程跟PostgreSQL, Oracle, MSSQL一比就是個(gè)笑話。二來存儲(chǔ)過程對(duì)于糙猛快、變化多的典型互聯(lián)網(wǎng)場景也比較雞肋。
??維護(hù)性與難調(diào)試的問題說到底是開發(fā)人員的知識(shí)與水平不足,如果你自己清楚知道怎么用和為什么要用存儲(chǔ)過程,那特么為什么不用?盡信書不如無書啊。
??對(duì)于一些領(lǐng)域模型相當(dāng)穩(wěn)定的場景,存儲(chǔ)過程其實(shí)是非常好的一個(gè)選擇。很多時(shí)候用存儲(chǔ)過程一次就能解決原來業(yè)務(wù)要幾次RT訪問才能搞定的事情,聚合Join處理一些常用的結(jié)果。另外數(shù)倉里搞OLAP寫的UDF說到底不也是存儲(chǔ)過程嘛。很多場景下合理利用數(shù)據(jù)庫的編程能力可以極大的提高開發(fā)效率與運(yùn)行效率。
馮若航(續(xù))
??上面是一年前的答案了。說起來,阿里一堆規(guī)矩實(shí)在是不爽。上個(gè)月干脆跳出去專職干DBA了。
??去了個(gè)新公司,用的PostgreSQL,數(shù)據(jù)庫用的溜到飛起。后端10萬行Go代碼,卻配著8萬行SQL,80%的業(yè)務(wù)邏輯放在數(shù)據(jù)庫。十幾組數(shù)據(jù)庫,一兩千個(gè)存儲(chǔ)過程,目前使用64組分片,加上林林總總小數(shù)據(jù)庫總共約兩百臺(tái),高峰期單機(jī)50kTPS。撐起了700萬日活的應(yīng)用。
至少有這么幾個(gè)優(yōu)點(diǎn):
性能:
??存儲(chǔ)過程消除不必要的網(wǎng)絡(luò)IO,所有事務(wù)型請(qǐng)求時(shí)延控制在1ms內(nèi),極大地提高了系統(tǒng)性能。
可擴(kuò)展性:
??擴(kuò)容通過傳統(tǒng)的分庫分表方式進(jìn)行。只要fork一份老庫的schema并rebalance數(shù)據(jù),即可完成擴(kuò)容。
靈活性:
??存儲(chǔ)過程在在數(shù)據(jù)庫和后端應(yīng)用之間提供了一個(gè)額外的接口層,當(dāng)?shù)讓訑?shù)據(jù)庫發(fā)生模式變更時(shí),可以對(duì)上層應(yīng)用保持透明;提供了巨大的靈活性,并降低了系統(tǒng)復(fù)雜性。
可管理性:
大多數(shù)上線、更新、降級(jí),是通過執(zhí)行SQL完成的;服務(wù)降級(jí)的時(shí)候,只需要把存儲(chǔ)過程替代為空函數(shù)即可。函數(shù)的調(diào)用頻次,執(zhí)行時(shí)間都可以直接從系統(tǒng)視圖中獲取。
- 甚至連推薦這種半事務(wù)半分析的功能也放在從庫里用存儲(chǔ)過程實(shí)現(xiàn),在10~100ms內(nèi)響應(yīng)。
??事實(shí)證明存儲(chǔ)過程在擴(kuò)展性上是沒有什么問題的。同時(shí)在靈活性、可管理性上也有突出的優(yōu)勢(shì)。移植性在我看來是個(gè)偽命題,絕大多數(shù)的產(chǎn)品,終其生命周期數(shù)據(jù)量都很難超出關(guān)系型數(shù)據(jù)庫的支持范疇。如果存在這種可能,那么選型的時(shí)候就該考慮好。
??調(diào)試更是無稽之談,敢在數(shù)據(jù)庫里跑的邏輯,哪一個(gè)不是開發(fā)和DBA重重審閱,就差形式化證明了。
??在我看來,《手冊(cè)》提到存儲(chǔ)過程的問題,沒有移植性根本就不算個(gè)理由。存儲(chǔ)過程的真正問題,既不是難以調(diào)試,也不是難以擴(kuò)展,唯一的致命問題是:太TM難招人了。
??團(tuán)隊(duì)素質(zhì)是使用存儲(chǔ)過程唯一的命門。這種開發(fā)模式對(duì)DBA、后端開發(fā)、架構(gòu)提出了極高的要求,只有精英小團(tuán)隊(duì)適用,或者真的是非常小的項(xiàng)目。泛用存儲(chǔ)過程需要后端程序員對(duì)數(shù)據(jù)庫有很深入的理解,對(duì)DBA的要求更為苛刻。很顯然,這種人也不需要再去看《阿里巴巴Java開發(fā)手冊(cè)》了……就是這個(gè)故事。
孤盡[《阿里巴巴JAVA開發(fā)手冊(cè)》主要作者]
??解釋一下這個(gè)事情:曾經(jīng)寫過近1200行的存儲(chǔ)過程,沒有辦法斷點(diǎn),下層數(shù)據(jù)結(jié)構(gòu)只是稍微變動(dòng),根本無法找到出錯(cuò)點(diǎn),只是提示一下說:ERROR:1064啥的。在數(shù)據(jù)庫遷移的時(shí)候,由于數(shù)據(jù)庫版本變更,居然存儲(chǔ)過程無法執(zhí)行。另外,業(yè)務(wù)上需要擴(kuò)展一下,那就是災(zāi)難性的啊。
??沒想到,我覺得毫無爭議的這一條,反而成了一個(gè)最大的爭議點(diǎn)。存儲(chǔ)過程只是單機(jī)時(shí)代的產(chǎn)物,并不適合互聯(lián)網(wǎng)時(shí)代。
阿里云云棲號(hào)
??任何軟件開發(fā)語言都是一種“綁定”或者說“限制”,一旦使用了一種語言開發(fā)出來的應(yīng)用,就會(huì)很難遷移到另一種語言。雖然并非絕對(duì),大部分情況下如此。
??回到問題本身,“Java開發(fā)手冊(cè)”就注定了已經(jīng)綁定在Java語言上了。但是你的應(yīng)用要綁定多少種語言呢?除了“Java”之外,是否還要綁定另外一種語言,比如用來寫存儲(chǔ)過程的各種“XXSQL”?
一旦使用了存儲(chǔ)過程,至少有三種潛在的“技術(shù)債務(wù)”是要考慮的:
1.多綁定了一種語言,因此無法容易的遷移到另一種數(shù)據(jù)庫上,例如Oracle的存儲(chǔ)過程就無法用于MySQL
2.多了一種程序語言,技術(shù)棧就提升了復(fù)雜度,對(duì)調(diào)試、測(cè)試、集成等等就會(huì)增加工作量和復(fù)雜度
3.存儲(chǔ)過程和Java不是一種類型的語言,因此需要有專業(yè)的知識(shí)(和人員,以及人員帶來的支出)來維護(hù)這部分程序最重要的是,存儲(chǔ)過程不是面向?qū)ο蟮?,Java和存儲(chǔ)過程都精通的人不好找,就算有,也很貴。
暴瘋
??拋開場景談規(guī)范都是耍流氓。
??以我的經(jīng)驗(yàn)管理超過3000張表,使用周期超過20年的庫、數(shù)據(jù)庫邏輯、包括外鍵 、強(qiáng)制約束、存儲(chǔ)過程接口是完全必須合理的。
??一個(gè)大庫很多公司用,你指望應(yīng)用層約束就是搞笑。天天說換db,我看到是 pb vb asp java 各個(gè)幾年就變了,公司在不在還不一定呢。
??同樣的邏輯過程里寫一份就好了,各種語言都能用。
??大量數(shù)據(jù)分析,把數(shù)據(jù)從數(shù)據(jù)庫讀出去,再寫回去累不累?不會(huì)調(diào)試、不會(huì)寫就去多練練。過程一樣可以寫的很優(yōu)雅,水平問題而已。
??《手冊(cè)》對(duì)我們Java開發(fā)人員來說是一份很值得參考的輔助性文檔,我們?cè)谧黾夹g(shù)選型時(shí),得依據(jù)實(shí)際開發(fā)場景和條件綜合考慮。通過瀏覽相關(guān)的資料和論壇,總的來看大家對(duì)存儲(chǔ)過程的功能和使用價(jià)值還是認(rèn)可的,學(xué)以致用,盡信書不如無書。
大致來說:
- 對(duì)于后續(xù)業(yè)務(wù)變動(dòng)可能性較小、架構(gòu)較穩(wěn)定的項(xiàng)目中建議多引用該技術(shù);
- 局部功能、單接口中數(shù)據(jù)庫交互需求大,且在緩存和中間件層無法處理的部分,建議使用該技術(shù);
- 在對(duì)業(yè)務(wù)擴(kuò)展不明確、后續(xù)數(shù)據(jù)體量拿不住的項(xiàng)目中,不建議使用該技術(shù);
- 在開發(fā)人員迭代快、交接較頻繁的項(xiàng)目中不建議使用該技術(shù);
??就到這里,希望你把你的看法和遇到的遭遇分享出來,大家互相白嫖~