转 ORM之硬伤
原貼 http://www.cnblogs.com/Barton131420/archive/2007/01/07/613955.html
園子里有些人,他們真以為自己明白了面向對象,然后裝著滿腹經綸,侃侃而談,一篇接一篇,不厭其煩地喊著ORM如何如何。你以為他真的明白“面向對象”么?其實,他對面向對象的理解僅限于教科書中的封裝、繼承和多態,或者再知道一點面向對象的若干原則但其實并不真正理解。
筆者愚鈍,入行多年尚不懂面向對象,只懂得用其形而不懂用其實。五年后的某一天終于開竅,明白了面向對象之實,也僅僅是一個開始而已。當又經歷了另一個五年的倦怠,發現并理解了設計模式、面向方面等技術作為面向對象的必要補充后,才算是徹悟!所以當我見過一個同學,尚未出校門已然徹悟,真是羞愧!
有一天面試的時候,我問一位同學,Framework和Library的區別是什么?他答不上來。而另一個同學略一思考就告訴我,你的程序會調用Library,而Framework會調用你的程序。雖然精辟,但我還是要補充:Framework通常也會提供一個Library,所以,Library是水平的,而Framework是垂直的,此處的“水平”和“垂直”是相對應用系統的層次設計而言的。如果沒有層次,其實Framework其實就是Library。Microsoft的Enterprise Library當然就是一個Library,無法代替Framework。
如果讓那位已經徹悟的同學舍棄ORM來實現復雜的業務功能,他當然無法接受。相反,如果讓一位抱著《Thinking in Java》似懂非懂的同學用ORM來實現同樣的功能,他也一樣無法接受。其中的一些同學非常擅于“雞蛋里挑骨頭”,于是園子里有了這樣一堆垃圾文章或者垃圾跟貼。另外一些同學不精于這樣的能力,所以仍在徬徨之中。
此乃ORM惟一之硬傷也!如果你不理解面向對象思想,就先試著去理解,然后再來討論ORM這個話題,并發表你的高見。
再說性能
ORM提供了所有SQL語句的生成,代碼人員遠離了數據庫概念。從一個概念需求(例如一個HQL)映射為一個SQL語句,并不需要什么代價,連1%的性能損失都沒有。真正的性能損失在映射過程中,更具體地講,是在對象實例化的過程中。我曾經做過一個試驗,以“計算第N個素數”這樣的命題。我采用Delphi寫Native Win32 Console程序,又采用C#寫CLR Console程序。兩者相比,令我大失所望。
| N | 結果 | 耗時 | |
| Delphi | C# | ||
| 1000 | 7927 | 0ms | 2ms |
| 10000 | 104743 | 16ms | 17ms |
| 100000 | 1299721 | 438ms | 324ms |
| 1000000 | 15485867 | 11437ms | 7823ms |
不知道各位是否已經明白了性能在哪兒損失了:內存分配。Native的內存分配與釋放都是非常耗時的操作系統行為。但在托管環境下,內存的釋放是GC干的事情,甚至不需要統計到耗時中,而內存的分配也是一件非常快捷的事情。當然,即使是快捷也還是需要耗時的。這讓我聯想到DataSet的性能。DataSet也是一種數據容器,但是卻沒有多少人抱怨DataSet的性能。如果你明白DataSet的機制,就會發現,DataStorage巧妙地規避了內存分配和耗時的問題。而我們的ORM無法解決每個對象實例在構造時分配內存所耗時間。我做了一個不精確的評估,相比DataSet,對象集合的性能損失大約占20%左右。
如果假定ORM并沒有比傳統的數據訪問方式耗費額外的IO的話,除此之外,ORM再沒有任何性能損失!
再回到前提條件:ORM并沒有比傳統的數據訪問方式耗費額外的IO。這個條件成立么?
“由于ORM的實體對象定義已經固定,所以即使我不需要某些字段,也一樣需要加載這些字段。”
OK,有的同學已經看出來了。額外定義一個視圖的實體對象即可。定義這些視圖的實體對象的確很麻煩,但是肯定比構造那些SQL并不斷地維護它簡單得多。
“當一張表中有1000萬行數據時,實例化1000萬個對象是不可能的。”
非常正確。難道你曾經成功地嘗試過將1000萬行數據加載到某個DataTable中并且沒有性能問題?從應用的角度來說,在一個模型中包含的實例數超過500行就有設計不當的嫌疑。我對Google的抱怨是:當搜索結果超過1000個時都會令我抓狂。讓我從1000行數據中找出我所需要的某一行,這是開發人員的思維,并不是用戶的思維。如果能夠在已有的結果中進行二次、三次或者多次進一步的篩選,可能更適合絕大多數人。我為什么不愿意在分頁中花太多的精力,其原因也是如此。我認為用戶的眼球只能接受100行以內的數據,超過這個行數就需要采用其它的方式,或者改善領域設計。所以,這個問題的答案是:你不可能需要一次載入1000萬行。
“當應用系統整體性能欠佳時,因為隱藏了數據訪問細節,從而無法找到快速優化的途徑。”
不能同意。幾乎每一個ORM框架都提供了非常可靠的數據庫訪問日志。通過這些日志分析性能損失將比直接使用SQL語句更可靠、更方便。
靈活性
ORM不夠靈活?我完全不能理解,我甚至不知道這個不夠靈活是與什么基準相比。相反,ORM可以讓你靈活地替換數據庫(當然這個優點并沒有非常重要的意義);在修改數據庫以后不需要修改服務層或者只需要進行簡單的修改;可以對某個服務進行單獨的測試;可以對服務進行不依賴數據庫的、上下文一級的擴展;可以進行更好的層次設計;......
不能實現所有的查詢條件
如果是想表達“每一個Select語句可以通過面向對象的方式進行查詢”的話,我覺得目前絕大部分ORM框架都已經很好地解決。我解決這一問題的基礎是:我不提供超越SQL ANSI92的能力,但覆蓋SQL ANSI92的所有功能。對于解決實際應用中的不足部分,采用運行時算法補充。Hibernate采用的是HQL這樣的方式,基本上SQL能夠做到的,HQL都無一例外可以做到。ECO采用的是OCL的方式,其功能可以完全覆蓋SQL。我的框架所實現的查詢目前我還沒有發現無法解決并必須利用Native SQL來實現的(因此我無法理解Hibernate3為什么要提供這樣的擴展)。Hibernate采用的策略是以面向對象為核心,換句話說,以持久化對象為終極目標,而以加載對象以持久化對象為前提。設計一個POJO,實例化,然后保存起來,下次使用的時候可以依樣載入即可。大規模的查詢并不是框架的核心目標。所以,如果你完全依賴Hibernate去持久化,我非常擔心你將來是否有機會用你的數據積累去做數據倉庫。而我的框架目標則不同。在持久化與加載兩個目標間我沒有主次之分。我也沒有超前到MDA,我的對象模型仍然基于數據庫的ER設計,我仍然提供一組非常清晰明了的數據庫視圖。
多表連接查詢
如果需要將多表的連接查詢結果轉換成一個二維視圖,顯然需要你再定義另一個視圖實體對象,將視圖映射到對象模型。如果你僅僅是要在一個對象實例的某個屬性中獲得另外一個對象的集合,似乎這不是DAL方式的優勢,而反而是ORM的優勢。將多個對象所依賴的多個對象放到同一個上下文中,顯然這是最好的一種方式。
統計查詢
從理論上講,ORM不適合做OLAP,不適合做太多統計查詢。其實這一點,我的框架已經提供了非常好的解決方案,對Aggregate到面向對象的視圖處理得非常好。
開發效率
提高開發效率僅僅是一個抽象的目標,具體的手段應該是兩個方面:一是IDE和輔助工具;一是適合將任務分解成多個解耦的部分從而可以通過增加人員來提升總的開發效率。雖然ORM僅僅是開發環節中很小的一部分,但是卻遍布應用系統中的每一角落,因而對開發效率影響較大。除了ORM,難道還有更好的選擇么?
ORM后,原來精湛的SQL技能變得毫無用武之地,讓人甚是失落,但這并不是ORM的過錯。
轉載于:https://www.cnblogs.com/JYun/archive/2007/01/07/614207.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
- 上一篇: activiti5第二弹----使用ac
- 下一篇: Activiti5第十一弹,流程监听器与