1. 程式人生 > >資料庫訪問的效能問題與瓶頸問題

資料庫訪問的效能問題與瓶頸問題

宣告

本文是一篇有爭議的文章,甚至有可能是一篇爭議非常大的文章,可能爭來爭去依然無法得到一個統一的意見。

場景

個別公司的技術決策者要求團隊的開發人員在編寫資料訪問層的時候,禁止在程式中出現任何的SQL語句,禁止使用Entity Library,禁止使用NBear、NHibernate、IBatis、Entity Framework等ORM框架,只允許使用儲存過程。試想一下,您的公司是否是這樣子的?您的身邊有沒有這樣的朋友,他們的公司存在這樣或類似這樣的情況嗎?

矛盾點

cry 對於開發人員來說,使用儲存過程的話,工作量比以前要大很多,而且涉及到表的欄位更改,專案重構也是個非常麻煩的問題,使用ORM很方便就可以實現資料的CRUD功能,多表操作也非常的容易,原來寫很少的程式碼就可以操作資料,現在卻要寫很多的程式碼。本來公司給的時間就短,專案緊,現在這麼一搞,工作量一下就增加了不少,再者,如果需求一旦發生變化,不可避免的資料庫就得增加或修改某些欄位,相應的儲存過程跟資料訪問層的方法都得做調整,開發人員的日子不好過了。

smile 對於公司的決策者來說,效能問題是不可以妥協的,無論付出多大代價,既然做出了決定,那麼就沒什麼好討論的。

結果

結果可想而知,最終是按照決策者的決定,開發人員加班加點的做開發,既然決策者都已經做了決定,似乎再討論用不用儲存過程就是一個非常敏感的話題,再討論類似的問題的話,開發人員所面臨的處境就可能是尷尬的,在某些公司甚至是危險的。無論怎樣,開發人員可能最終都很難改變決策者的決定。

決策者的心聲

帶著這些疑惑,我跟多位決策者進行溝通,蒐集了他們的意見,總結下來的話,大概就是以下幾點:

  1. 效能問題。經過測試,使用ORM比直接呼叫儲存過程慢10倍。如果是做軟體專案或軟體產品,使用ORM問題不大,可是如果是以運營為主(訪問量較大)的Web網站,效能上就會有問題。
  2. 併發問題。一旦訪問量較大並且達到一定數量級的時候,ORM就可能會出現併發問題。
  3. DBA的能力受限。一旦出現效能問題,如果是按照寫儲存過程的方式來做,公司可以招來技術實力強的DBA直接改儲存過程進行優化,而如果是使用ORM的話,那麼DBA就很難進行優化,因為DBA很難讀懂ORM寫的程式,更不知道ORM內部的實現方式,這樣一來,DBA的能力就得不到施展。
  4. 不願意被微軟綁架。以Entity Framework為例,Entity Framework不是開源的,如果出現效能問題,不能夠看到原始碼,這可能是一個風險。再者,一個強有力的公司強有力的團隊,如果沒有自己的技術,總是使用微軟的不開源的框架,這怎麼可以?
  5. 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是可以跟程式設計師配合,利用SQLProfile等工具,看到最終SQL語句是如何執行的。也就是說,DBA的能力也是依然可以發揮出來的,只不過是需要跟程式設計師配合而已,或者DBA需要熟悉如何除錯、跟蹤。如果說全部寫儲存過程了,DBA能力是放開了,可是程式設計師的能力就受限了,譬如說,在進行大批量的資料插入的時候,大家都知道,.ADO.NET2.0的一個新特性SqlBulkCopy是多麼的快,估計這是DBA無法優化的。對SqlBulkCopy不熟悉的朋友,請參考《SQLServer中批量插入資料方式的效能對比》。

很多時候,一個軟體效能的優化,需要從整體去考慮,並不一定是說出現資料庫效能問題,就一定是DBA的責任,或者說一定是程式設計師的責任。在DBA跟程式設計師之間難道就真的像插銷跟插板之間那樣,職責分的特別的清楚?很多時候我們得充分利用儲存過程的特性,跟.NET平臺的一些優良特性,選擇適合我們的來進行開發,沒有什麼是最佳的,但是對我們來說,適合我們就好。

從另外的角度考慮,其實在專案初期,DBA就應該參與進來,進行資料庫的設計了,而一旦資料庫設計好了,設計得並不規範,儲存過程也些了成千上萬了,將來一旦出現效能問題,相信也夠DBA喝一壺的。

4.不願意被微軟綁架。這個觀點倒是讓我感覺到意外,至少我們很多都在用微軟的.NET Framework,我們使用微軟的SQL Server資料庫,如果說我們被綁架,可能現在就已經被綁架了,SQLServer的儲存過程跟Oracle、Mysql的儲存過程是不一樣的,如果將來進行資料庫的遷移,那麼可想而知後果是怎樣的。到底怎樣才是真正的被綁架?

5..Net與Java孰好孰壞?

關於這個問題的討論,一直就是個無休止的討論。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.

其次,如果表中有多個列,要更新的也是多列,儲存過程的侷限性就出來了。

再次宣告:文中觀點僅代表個人觀點,如果您有不同意見,歡迎共同討論。

最後,給大家分享個幽默視訊,來緩解下這種緊張而激烈的爭論吧。

作者:深山老林
出處:http://wlb.cnblogs.com/
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連線,否則保留追究法律責任的權利。 9 0 (請您對文章做出評價)