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