|
聲明:
本文是一篇有爭議的文章,甚至有可能是一篇爭議非常大的文章,可能爭來爭去依然無法得到一個統一的意見。
場景
個別公司的技術決策者要求團隊的開發人員在編寫數據訪問層的時候,禁止在程序中出現任何的SQL語句,禁止使用Entity Library,禁止使用NBear、NHibernate、IBatis、Entity Framework等ORM框架,只允許使用存儲過程。試想一下,您的公司是否是這樣子的?您的身邊有沒有這樣的朋友,他們的公司存在這樣或類似這樣的情況嗎?
矛盾點
對于開發人員來說,使用存儲過程的話,工作量比以前要大很多,而且涉及到表的字段更改,項目重構也是個非常麻煩的問題。使用ORM很方便就可以實現數據的CRUD功能,多表操作也非常的容易,原來寫很少的代碼就可以操作數據,現在卻要寫很多的代碼。本來公司給的時間就短,項目緊,現在這么一搞,工作量一下就增加了不少,再者,如果需求一旦發生變化,不可避免的數據庫就得增加或修改某些字段,相應的存儲過程跟數據訪問層的方法都得做調整,開發人員的日子不好過了。
對于公司的決策者來說,性能問題是不可以妥協的,無論付出多大代價,既然做出了決定,那么就沒什么好討論的。
結果
結果可想而知,最終是按照決策者的決定,開發人員加班加點的做開發,既然決策者都已經做了決定,似乎再討論用不用存儲過程就是一個非常敏感的話題,再討論類似的問題的話,開發人員所面臨的處境就可能是尷尬的,在某些公司甚至是危險的。無論怎樣,開發人員可能最終都很難改變決策者的決定。
決策者的心聲
帶著這些疑惑,我跟多位決策者進行溝通,搜集了他們的意見,總結下來的話,大概就是以下幾點:
- 性能問題。經過測試,使用ORM比直接調用存儲過程慢10倍。如果是做軟件項目或軟件產品,使用ORM問題不大,可是如果是以運營為主(訪問量較大)的Web網站,性能上就會有問題。
- 并發問題。一旦訪問量較大并且達到一定數量級的時候,ORM就可能會出現并發問題。
- DBA的能力受限。一旦出現性能問題,如果是按照寫存儲過程的方式來做,公司可以招來技術實力強的DBA直接改存儲過程進行優化,而如果是使用ORM的話,那么DBA就很難進行優化,因為DBA很難讀懂ORM寫的程序,更不知道ORM內部的實現方式,這樣一來,DBA的能力就得不到施展。
- 不愿意被微軟綁架。以Entity Framework為例,Entity Framework不是開源的,如果出現性能問題,不能夠看到源代碼,這可能是一個風險。再者,一個強有力的公司強有力的團隊,如果沒有自己的技術,總是使用微軟的不開源的框架,這怎么可以?
- Entity Framework是微軟的產品,微軟的產品只適合中小型的公司做開發,大的互聯網公司是不敢用的,甚至他們可能采用Java+Oracle來做,一旦達到一定數量級,微軟的東西就可能會出現問題。
筆者的心聲
在充分理解了決策者的心聲以后,我思緒萬千,心中久久不能平靜。終于,在把很多東西看淡,拋開雜念,在這樣一個寧靜的夜晚,也坦誠的把我的想法一一闡述,分別針對決策者的心聲,談一談我的個人看法。
1. 到底什么是性能問題?存在不存在性能問題?
來看下測試是如何做的,使用存儲過程進行插入或刪除操作,分別使用存儲過程和Entity Framework,循環10000次或者1000000次操作,然后整體上存儲過程要比使用Entity Framework要快10倍。實際場景是怎樣的呢?
實際的場景是用戶點擊頁面上的按鈕,執行了1次操作,我們假定按照寫存儲過程的方式來做,用戶這1次操作可能需要0.001秒,而使用Entity Framework要慢10倍,用了0.01秒,那么這0.001秒比0.01秒的確是快10倍,但是對用戶來說,可能根本就沒有明顯的差距,因為這么微弱的時間用戶是體會不出來的。我們開發的程序,對用戶來說,我們的產品會不會因為這0.001秒跟0.01秒的差距而打折扣呢?這微弱的差距是嚴重性能問題?還是可以忽略不計?
2. 到底存在不存在并發問題?
誠然,可能之前有團隊使用ORM開發高并發的項目,他們在運營中出現了并發問題,可是DBA又無法查出來到底是什么地方導致了并發問題,最終把一切的一切歸咎在ORM上。
親愛的朋友們,讓我們理智的冷靜的來分析下兩者的技術實現上的不同吧。
直接調用存儲過程:打開數據庫連接--》執行編譯好的數據庫語句--》關閉數據庫連接;
ORM:打開數據庫連接--》把對象解釋成SQL語句--》執行SQL操作--》關閉數據庫連接。
通過對比,我們可以發現,ORM就可以比作是一個SQL生成器,它把對象解釋,拼一個SQL語句出來,然后在執行這個SQL語句,由于還需要解釋,就相當于多了一步翻譯的工作。因此,就比存儲過程慢了一點點,那么慢的這一點點會不會出現并發問題?我的意見是并發問題多半是由于鎖的影響,只要不產生鎖,就不會有并發問題。正因為如此,高并發的項目開發,多半是忌諱使用事務,有的程序員手寫異常后的數據庫回滾語句(有些滑稽哈,但事實上就是這樣),項目中也不推薦使用游標跟觸發器。
3. DBA能力受限。誠然,DBA看不懂ORM寫的程序,更加不明白ORM內部的實現原理。但是,DBA是可以跟程序員配合,利用SQL Profiler等工具,看到最終SQL語句是如何執行的。也就是說,DBA的能力也是依然可以發揮出來的,只不過是需要跟程序員配合而已,或者DBA需要熟悉如何調試、跟蹤。如果說全部寫存儲過程了,DBA能力是放開了,可是程序員的能力就受限了,譬如說,在進行大批量的數據插入的時候,大家都知道,.ADO.NET2.0的一個新特性SqlBulkCopy是多么的快,估計這是DBA無法優化的。對SqlBulkCopy不熟悉的朋友,請參考《SQLServer中批量插入數據方式的性能對比》。
很多時候,一個軟件性能的優化,需要從整體去考慮,并不一定是說出現數據庫性能問題,就一定是DBA的責任,或者說一定是程序員的責任。在DBA跟程序員之間難道就真的像插銷跟插板之間那樣,職責分的特別的清楚?很多時候我們得充分利用存儲過程的特性,跟.NET平臺的一些優良特性,選擇適合我們的來進行開發,沒有什么是最佳的,但是對我們來說,適合我們就好。
從另外的角度考慮,其實在項目初期,DBA就應該參與進來,進行數據庫的設計了,而一旦數據庫設計好了,設計得并不規范,存儲過程也寫了成千上萬了,將來一旦出現性能問題,相信也夠DBA喝一壺的。
4. 不愿意被微軟綁架。這個觀點倒是讓我感覺到意外,至少我們很多都在用微軟的.NET Framework,我們使用微軟的SQL Server數據庫,如果說我們被綁架,可能現在就已經被綁架了,SQLServer的存儲過程跟Oracle、Mysql的存儲過程是不一樣的,如果將來進行數據庫的遷移,那么可想而知后果是怎樣的。到底怎樣才是真正的被綁架?
關于這個問題的討論,一直就是個無休止的討論。scottgu把這個比作是“帶有宗教性質的技術爭論”。誠然,討論這樣的問題的確令人討厭,而且是浪費時間,而且討論的雙方都深切的關注著。討論來討論去最終也不會有結果。
在目前所運行的軟件系統中,我們可以看到其背后的平臺、語言等是各種各樣,MySpace是基于.NET平臺的,淘寶網是基于Java的,而Google則推崇使用Python,許多大型的電力系統還依然運行在C++平臺上,最關鍵的一點,.NET并不是沒有在大型項目中應用。只不過是Java起步早,.NET起步晚而已,要在前幾年,Java做的大型項目的確是比.NET的大型項目要多。
很多時候,即使是使用相同的開發語言,不同的程序員開發的程序效率就差30倍以上,甚至幾千倍以上,這點好不夸張。誠然,每門技術自有其缺點,但它們也都自有其優點,如果它的優點恰好能符合你的需要,用它就好了。重要的是,你有沒有使用好它的能力。
總結
其實總結就不必了,說點題外話吧。存儲過程在單條執行操作的時候,的確要比使用ORM要快,可是如果是執行批量的操作,使用存儲過程就會非常的費勁。之前我是這樣做的。假定更新1000條數據,數據庫里只有2個字段,循環調用1000次存儲過程需要2分鐘左右,當時我把要更新的id以參數的形式逗號分隔傳入存儲過程,在存儲過程中循環執行1000條數據,發現時間跟循環調用1000次存儲過程的時間是差不太多的,最終進行了改進,改進的方法嘛,還是把要更新的Id以參數形式逗號分隔傳入存儲過程,然后使用update table set value=’value’ where id in select id in 分隔函數(id1,id2,id3…..),經過這種方式,更新1000條數據的時間從2分鐘變成了200毫秒,可是問題依然不完美,方法存在局限性。
首先,使用這種方法參數的長度是有限制的,varchar類型最大不超過8000,nvarchar類型最大長度不超過4000。
其次,如果表中有多個列,要更新的也是多列,存儲過程的局限性就出來了。
再次聲明:文中觀點僅代表個人觀點,如果您有不同意見,歡迎共同討論。
最后,給大家分享個幽默視頻,來緩解下這種緊張而激烈的爭論吧:
NET技術:數據庫訪問的性能問題與瓶頸問題,轉載需保留來源!
鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。