MySQL 中存儲過程的使用


    關於 MySQL 的存儲過程,我所了解的一些有規模的公司,對於使用存儲過程實現業務邏輯都有嚴格的限制。我這里搜羅了一些資料,結合自身的經驗,總結一些自己關於 MySQL 中存儲過程使用的認識。由於水平有限,如有紕漏錯誤,還請多拍磚。

 

    存儲過程的優點主要包括以下幾點:

 

1. 性能提高。相對於不使用存儲過程來說的,因為存儲過程在創建的時候,數據庫已經對其進行了一次解析和優化,而后每次調用都不會再次編譯,這相對於傳統的SQL語句中每次調用都需要編譯的情況來說,性能有所提高,存儲過程經過編譯之后會比單獨一條一條執行要快。而存儲過程一旦執行,在內存中就會保留一份,這樣下次再執行同樣的存儲過程時,可以從內存中直接中讀取。

2. 重用性強。存儲過程使用名字即可執行,也就是傳說中的“一次編寫,隨便調用”。並且是透明的,因為保存在數據庫里所以對任何應用來說都可以使用。新的應用只需要調用相應的存儲過程就可以得到相應的數據服務。這樣不僅提高了重用性,還減少了出錯的幾率,也會加快開發速度。同時不依賴某種宿主語言,如果用多種語言開發,某些通用代碼不用重復。

3. 減少網絡流量。這一點對於小數據量的時候體現的並不明顯。存儲過程直接就在數據庫服務器上跑,所有的數據訪問都在服務器內部進行,不需要傳輸數據到其它終端,因此減少了應用服務器同數據庫服務器的通信頻率。調用一個行數不多的存儲過程與直接調用SQL語句的網絡通信量可能不會有很大的差別,可是如果存儲過程包含上百行SQL語句,那么其性能就會比一條一條的調用SQL語句有較大的提升。

4. 安全性提高。存儲過程是通過向用戶授予權限(而不是基於表),它們可以提供對特定數據的訪問,而且參數化的存儲過程可以防止SQL注入攻擊,在一定程度上保證了安全性。DBA可以對那些沒有權限訪問數據庫中的表的應用,賦予存儲過程的權限來獲得數據服務,這個時候這些存儲過程好像我們編程里面的“接口”。對於安全性要求很高的系統,例如銀行,基本上常用的操作都是通過存儲過程或者函數來進行的,這樣完全對應用”隱藏“了表。

5. 靈活性增強。由於存儲過程可以使用流程控制語句來編寫,使得它有着很強的靈活性,可以根據實際情況來執行不同的SQL語句,而不是只能單純的簡單的執行命令。而且存儲過程還可以修改其邏輯而其他部分不用改變,也就是說,我們的表的結構改變了,我們可能只需要修改相應的存儲過程即可,我們的Java或者PHP等程序不需要改變。

6. 減少工作量。當業務復雜的時候,如果我們不使用存儲過程,那么就會需要先從數據庫中取出來數據,然后經過計算,再放入到數據庫中。這些都是有開銷的,其中包括我們的Java或者PHP等程序連接數據庫獲取結果集等若干操作。如果我們使用了存儲過程,那么直接在MySQL中就能完成修改。並且可以分布式工作,應用程序和數據庫的編碼工作可以分別獨立進行,而不會相互壓制。

7. 可維護性高。更新存儲過程通常比更改、測試以及重新部署程序集需要較少的時間和精力。在生產環境下,可以通過直接修改存儲過程的方式修改業務邏輯(或bug),而不用重啟服務器。但這一點便利很多時候被濫用了。比如:直接在正式服務器上修改存儲過程,而沒有經過完整的測試,后果可能會非常嚴重。

 

    好,上面說了存儲過程的優點,再來看看存儲過程的缺點:

 

1. 編寫和調試麻煩。MySQL本身並沒有很像樣的IDE來開發存儲過程,我們很多時候還是需要一行一行的老老實實手寫,這樣就會比較麻煩。而存儲過程的調試也是一個問題,沒有很像樣的調試工具,很多時候是用print來調試,而且在使用slowlog對MySQL進行性能分析時,只能記錄整個存儲過程的執行情況,卻無法記錄存儲過程內具體語句的執行情況,對於調試長達數百行SQL的存儲過程簡直是蛋疼。

2. 性能優勢不明顯。在運行速度上,對於大多數的SQL語句來說,編譯SQL的時間開銷並不是很大,但是執行存儲過程還需要檢查權限等一些其他開銷,所以,對於很簡單的SQL,存儲過程並沒有很大的性能優勢。而且,數據庫畢竟主要用來做數據存取的,並不適合進行復雜的業務邏輯操作,承擔業務壓力會占用大量的系統資源(cpu、memory)。

3. 贅余功能。通常情況下,數據庫服務器只向內網中的應用服務器提供服務,而且連接數據庫的用戶往往是同一個。對於除金融領域外的其他大多數程序來說,安全性方面的需求往往小於性能、功能等其他方面。所以,對於安全性方面的情況看上去很好,實際上優點有些多余。

4. 可移植性差。當我們的程序要更換數據庫的時候,它的移植性相對於不適用存儲過程要更復雜。而且MySQL的存儲過程功能比起Oracle、SQLserver、乃至PostgreSQL 都要較弱一些。

5. 本末倒置。SQL本身是一種結構化查詢語言,加上了一些控制(賦值、循環和異常處理等),但不是OO的,本質上還是過程化的,大量采用存儲過程進行業務邏輯的開發時,由於不支持面向對象的設計,無法采用面向對象的方式將業務邏輯進行封裝,從而無法形成通用的可支持復用的業務邏輯框架,面對復雜的業務邏輯,過程化的處理會很吃力。

6. 拓展性差。像MySQL這樣的關系型數據庫,出現CPU和IO瓶頸時,極難擴展,但是應用服務器出現CPU和IO瓶頸,特別是采用SNA架構的情況下,理論上可以獲得無限的水平擴展能力,只需要加服務器就行了。這個方法比任何方法都見效快,而且往往也是成本最低的。

              

總結:

    對於MySQL來說,通常情況下,除了某些非常依賴數據處理的操作,其他的業務邏輯不應該使用存儲過程來實現,而應該由應用層實現。

 

    PS:題外話,並不是每個應用的瓶頸都在數據庫端。即便瓶頸在數據庫端,具體問題具體分析,也要功能、性能、安全、成本、效率等多方面權衡,才能做出最合適的選擇。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM