公司的系統是自主開發的,歷史比較悠久,有不少是傳統C/S架構,采用存儲過程來處理業務邏輯。
近來做新系統的時候,我采用了三層架構,拋棄存儲過程改用ORM。
有同事問及不用存儲過程的理由,我想了一下,對存儲過程做了如下總結。
本人經驗和水平有限,總結有所偏頗,還請大家糾察。
優點
1.在生產環境下,可以通過直接修改存儲過程的方式修改業務邏輯(或bug),而不用重啟服務器。但這一點便利被許多人濫用了。有人直接就在正式服務器上修改存儲過程,而沒有經過完整的測試,後果非常嚴重。
2.執行速度快。存儲過程經過編譯之後會比單獨一條一條執行要快。但這個效率真是沒太大影響。如果是要做大數據量的導入、同步,我們可以用其它手段。
3.減少網絡傳輸。存儲過程直接就在數據庫服務器上跑,所有的數據訪問都在服務器內部進行,不需要傳輸數據到其它終端。但我們的應付服務器通常與數據庫是在同一內網,大數據的訪問的瓶頸會是硬盤的速度,而不是網速。
4.能夠解決presentation與數據之間的差異,說得文藝青年點就是解決OO模型與二維數據持久化之間的阻抗。領域模型和數據模型的設計可能不是同一個人(一個是SA,另一個是DBA),兩者的分歧可能會很大——這不奇怪,一個是以OO的思想來設計,一個是結構化的數據來設計,大家互不妥協——你說為了軟件的彈性必須這麼設計,他說為了效率必須那樣設計,為了抹平鴻溝,就用存儲過程來做數據存儲的邏輯映射(把屬性映射到字段)。好吧,台下已經有同學在叨咕ORM了。
5.方便DBA優化。所有的SQL集中在一個地方,DBA會很高興。這一點算是ORM的軟肋。不過按照CQRS框架的思想,查詢是用存儲過程還是ORM,還真不是問題——DBA對數據庫的優化,ORM一樣會受益。況且放在ORM中還能用二級緩存,有些時候效率還會更高。
缺點
1.SQL本身是一種結構化查詢語言,加上了一些控制(賦值、循環和異常處理等),但不是OO的,本質上還是過程化的,面對復雜的業務邏輯,過程化的處理會很吃力。這一點算致命傷。
2.不便於調試。基本上沒有較好的調試器,很多時候是用print來調試,但用這種方法調試長達數百行的存儲過程簡直是噩夢。好吧,這一點不算啥,C#/java一樣能寫出噩夢般的代碼。
3.沒辦法應用緩存。雖然有全局臨時表之類的方法可以做緩存,但同樣加重了數據庫的負擔。如果緩存並發嚴重,經常要加鎖,那效率實在堪憂。
4.無法適應數據庫的切割(水平或垂直切割)。數據庫切割之後,存儲過程並不清楚數據存儲在哪個數據庫中。
5.精通SQL的新手越來越少——不要笑,這是真的,我面試過N多新人,都不知道如何創建全局臨時表、不知道having、不知道聚集索引和非聚集索引,更別提游標和提交叉表查詢了。好吧,這個缺點算是湊數用的,作為屌絲程序員,我們的口號是:沒有不會的,只有不用的。除了少數有語言潔癖的人,我相信精通SQL只是時間問題。
總結
存儲過程最大的優點是部署的方便性——可以在生產環境下直接修改——雖然濫用的後果很嚴重。
存儲過程最大的缺點是SQL語言本身的局限性——我們不應該用存儲過程處理復雜的業務邏輯——讓SQL回歸它“結構化查詢語言”的功用吧。