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