什麼情況下才應該使用存儲過程而不是用程序來對數據做操作?


存儲過程的好處是,你可以給一個用戶(通常是客戶端使用來登陸的connection string,而不是指活人)Execute許可權。這個客戶端不能Select,Update,Insert,Delete,只能運行你指定的幾個存儲過程。不僅有效從源頭上杜絕SQL注入(都不能拼SQL還談何注入),而且就算你的客戶端給人逆了,他也只能調用你給定的幾個存儲過程,幾乎沒有風險。

而且存儲過程跟資料庫的schema是解耦的。你增加刪除column跟客戶端毫無關係,只要你deploy的時候同時改掉存儲過程就可以了。而且在也沒有那些修改了column之後讓那些使用Select *的客戶端傻逼的事情了。好處簡直無限多。

唯一的壞處就是不能拼條件了。所以只要你不需要拼條件,不需要任意數量的遞歸join(其實這也可以用存儲過程來做只要你懂得設計參數),那就應該使用存儲過程。


在客戶端程序員水平不如dba的時候。。。


分以下兩種情況來看吧:

1.
如果處理的邏輯不是太複雜,也就是邏輯的時間複雜度不高,可以放進存儲過程,因為如果太複雜(例如有很多巨耗CPU資源的操作),會加大資料庫伺服器的壓力,從而影響資料庫伺服器對其它請求的響應。而本應以運行程序邏輯為本職的應用伺服器,卻晾在一旁打醬油,你認為這樣真的好嗎?

2.
相反,如果邏輯不太複雜,但是需要訪問的數據量是巨量的,那麼就更適合放進存儲過程處理(注意處理好表鎖定的問題),因為當你讀取上千萬條件數據並把它們傳進應用伺服器再來處理,除了對資料庫伺服器有壓力,對應用處理器的內存壓力也很大的,倒不如直接在資料庫伺服器處理完它。這種情況時,儘管在讀取大數據量時,其實無論用哪種方法,資料庫伺服器的磁碟IO承受的壓力都是一樣的,但如果放在代碼里處理,也就是需要傳到應用伺服器端處理,那麼就會對網路IO也形成了壓力。如果這種操作頻繁的話,會對網路IO形成壓力脈衝。有可能影響同一網路上的其它應用。


沒有這樣的需求,因為程序都可以實現,盡量用程序的好處就是好理解,好維護。


我唯一認同使用存儲過程的條件:業務永遠不變.但你確定你寫完之後一輩子都不會改了.那就可以用了.

使用存儲過程.當業務發生變化時.就像把自己1個月前啦的屎吃回去..


當你完全放棄資料庫的可移植性的時候。


這裡有個應用場景例子(可以參考一下裡面的第三章-並發優化):

Java高並發秒殺API之高並發優化教程-慕課網


需要對大量數據map/reduce操作的場合。這種情況把原始數據選出來傳給資料庫客戶端處理是很低效的,某些情況下是不可行的


  1. 減少數據的round-trip

  2. 對性能有一定追求

  3. 業務邏輯比較簡單 (也有把很複雜邏輯寫在sp裡面的做法,個人覺得不利於未來的維護,放程序裡面比較好)

我現在在嘗試用PostgreSQL的存儲過程來實現整個應用,只是加一個極薄的HTTP伺服器層處理Web請求,轉成資料庫調用。PG支持用各種編程語言來寫存儲過程,比如Python、Perl、JavaScript等,還有它自帶的PL/pgSQL,組合起來使用應該比較爽。

使用存儲過程的原因主要是離數據近,免去了數據從DB搬運到應用伺服器的消耗;同時架構上也變簡單了,省去了程序里建對象模型和ORM處理的麻煩,直接使用資料庫表結構作為模型。


之前也曾想過這個問題,看到這個問題正好把之前不太成熟的想法總結一下(也許有很多錯誤),因為沒有寫過存儲過程和程序,所以不涉及實現細節,都是從宏觀的角度想的,歡迎拍磚。

存儲過程對數據操作也就是將數據操作交給DB層來做,程序對數據做操作是將數據操作交由DB層之上的application軟體層來做。

DB層對於數據操作的優勢是數據計算和大數據量的處理,application層的優勢則是業務邏輯的實現。

- 很久以前的DB因為硬體和功能的限制,更多的被視為保存數據的地方,數據存儲的一致性和安全性是DB最初的主要功能,數據的計算和操作多由app層實現。後來隨著DB的發展,硬體上的限制也越來越少,其計算和數據操作的功能越來越強大,於是越來越多的將數據操作由app層轉向DB層,因為數據操作是DB最擅長的,DB將數據處理後將結果交給App層既能使上層軟體更輕量,又能減少io。

- 跟application的類型有關,對於OLAP類應用,數據計算和分析的軟體,大量的數據操作和計算放到DB層會比較快。OLTP類的應用可能業務邏輯的要求多一些,數據操作的複雜度和數據量相對小一些,數據操作即使在App層實現也不會影響太大(?)。

- 應用軟體的可移植性(不知道這個詞這麼用對不對,想說DB independency),軟體可能需要支持多個資料庫,比如無論DB層用Oracle的還是IBM的資料庫,上層app軟體都要支持。將更多的數據操作邏輯放到app軟體層可以減少為了支持不同資料庫而需要在DB存儲過程上做的改動。

暫時想到這些,歡迎補充、糾錯。


從安全性考慮 可以grant一個procedure給用戶 也可以revoke用戶許可權 這樣的話就算是hake黑了別人的密碼也不怕 因為只有多票所說的 都只能用提供的procedure還怎麼sql注入 還有就是可以復用 類似類的方法 可以實現重複的使用對於大型的開發還是很大益處 有個問題就是procedure如何跟事務一起使用保證原子性 這點有點少用 例如 我要統計總數 而現在有用戶新增進來 這個肯定是用到資料庫的鎖機制 具體落實到應用層面如何實現?


業務相對不穩定,需要長期進行調試時


輸入的數據比輸出的數據多得多的操作。


推薦閱讀:

程序員們怎麼理解各種計算機書里抽象的概念呢?
c++大作業怎麼用windows API 做個窗口程序?不用MFC或者是QT這些工具。
如何評價noip2016初賽題?
如何練習編程的手速?
開發一款手游的工作量是怎樣的?

TAG:資料庫 | 程序員 | 編程 | NET | 存儲過程 |