乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      ORM之硬傷 - Kanas.Net Blog - 博客園

       xnet 2007-01-10

      ORM之硬傷

      園子里有些人,他們真以為自己明白了面向?qū)ο螅缓笱b著滿腹經(jīng)綸,侃侃而談,一篇接一篇,不厭其煩地喊著ORM如何如何。你以為他真的明白“面向?qū)ο?#8221;么?其實(shí),他對(duì)面向?qū)ο蟮睦斫鈨H限于教科書中的封裝、繼承和多態(tài),或者再知道一點(diǎn)面向?qū)ο蟮娜舾稍瓌t但其實(shí)并不真正理解。
      筆者愚鈍,入行多年尚不懂面向?qū)ο?,只懂得用其形而不懂用其?shí)。五年后的某一天終于開竅,明白了面向?qū)ο笾畬?shí),也僅僅是一個(gè)開始而已。當(dāng)又經(jīng)歷了另一個(gè)五年的倦怠,發(fā)現(xiàn)并理解了設(shè)計(jì)模式、面向方面等技術(shù)作為面向?qū)ο蟮谋匾a(bǔ)充后,才算是徹悟!所以當(dāng)我見過一個(gè)同學(xué),尚未出校門已然徹悟,真是羞愧!
      有一天面試的時(shí)候,我問一位同學(xué),F(xiàn)ramework和Library的區(qū)別是什么?他答不上來。而另一個(gè)同學(xué)略一思考就告訴我,你的程序會(huì)調(diào)用Library,而Framework會(huì)調(diào)用你的程序。雖然精辟,但我還是要補(bǔ)充:Framework通常也會(huì)提供一個(gè)Library,所以,Library是水平的,而Framework是垂直的,此處的“水平”和“垂直”是相對(duì)應(yīng)用系統(tǒng)的層次設(shè)計(jì)而言的。如果沒有層次,其實(shí)Framework其實(shí)就是Library。Microsoft的Enterprise Library當(dāng)然就是一個(gè)Library,無法代替Framework。
      如果讓那位已經(jīng)徹悟的同學(xué)舍棄ORM來實(shí)現(xiàn)復(fù)雜的業(yè)務(wù)功能,他當(dāng)然無法接受。相反,如果讓一位抱著《Thinking in Java》似懂非懂的同學(xué)用ORM來實(shí)現(xiàn)同樣的功能,他也一樣無法接受。其中的一些同學(xué)非常擅于“雞蛋里挑骨頭”,于是園子里有了這樣一堆垃圾文章或者垃圾跟貼。另外一些同學(xué)不精于這樣的能力,所以仍在徬徨之中。

      此乃ORM惟一之硬傷也!如果你不理解面向?qū)ο笏枷?,就先試著去理解,然后再來討論ORM這個(gè)話題,并發(fā)表你的高見。

      再說性能
      ORM提供了所有SQL語句的生成,代碼人員遠(yuǎn)離了數(shù)據(jù)庫概念。從一個(gè)概念需求(例如一個(gè)HQL)映射為一個(gè)SQL語句,并不需要什么代價(jià),連1%的性能損失都沒有。真正的性能損失在映射過程中,更具體地講,是在對(duì)象實(shí)例化的過程中。我曾經(jīng)做過一個(gè)試驗(yàn),以“計(jì)算第N個(gè)素?cái)?shù)”這樣的命題。我采用Delphi寫Native Win32 Console程序,又采用C#寫CLR Console程序。兩者相比,令我大失所望。

      N

      結(jié)果

      耗時(shí)

      Delphi

      C#

      1000

      7927

      0ms

      2ms

      10000

      104743

      16ms

      17ms

      100000

      1299721

      438ms

      324ms

      1000000

      15485867

      11437ms

      7823ms

      該命題采用的算法是找出第N個(gè)素?cái)?shù)以前的所有素?cái)?shù),開辟一個(gè)內(nèi)存區(qū)存貯這些素?cái)?shù)。在Delphi中我用鏈表,在C#中我用List<int>。實(shí)際的結(jié)論是:當(dāng)列表足夠大時(shí),鏈表的性能遠(yuǎn)不及List<int>。當(dāng)然,如果每個(gè)鏈表節(jié)點(diǎn)只裝一個(gè)元素,這種差異會(huì)更明顯。事實(shí)上,我測(cè)試過每個(gè)鏈表節(jié)點(diǎn)所裝的元素個(gè)數(shù)做了一個(gè)階梯試驗(yàn),從30個(gè)、254個(gè)、510個(gè)、1022個(gè)到2046個(gè),每個(gè)節(jié)點(diǎn)所裝載的元素?cái)?shù)越多,耗時(shí)越短,最終越來越接近C#的List<int>。
      不知道各位是否已經(jīng)明白了性能在哪兒損失了:內(nèi)存分配。Native的內(nèi)存分配與釋放都是非常耗時(shí)的操作系統(tǒng)行為。但在托管環(huán)境下,內(nèi)存的釋放是GC干的事情,甚至不需要統(tǒng)計(jì)到耗時(shí)中,而內(nèi)存的分配也是一件非??旖莸氖虑?。當(dāng)然,即使是快捷也還是需要耗時(shí)的。這讓我聯(lián)想到DataSet的性能。DataSet也是一種數(shù)據(jù)容器,但是卻沒有多少人抱怨DataSet的性能。如果你明白DataSet的機(jī)制,就會(huì)發(fā)現(xiàn),DataStorage巧妙地規(guī)避了內(nèi)存分配和耗時(shí)的問題。而我們的ORM無法解決每個(gè)對(duì)象實(shí)例在構(gòu)造時(shí)分配內(nèi)存所耗時(shí)間。我做了一個(gè)不精確的評(píng)估,相比DataSet,對(duì)象集合的性能損失大約占20%左右。
      如果假定ORM并沒有比傳統(tǒng)的數(shù)據(jù)訪問方式耗費(fèi)額外的IO的話,除此之外,ORM再?zèng)]有任何性能損失!
      再回到前提條件:ORM并沒有比傳統(tǒng)的數(shù)據(jù)訪問方式耗費(fèi)額外的IO。這個(gè)條件成立么?
      由于ORM的實(shí)體對(duì)象定義已經(jīng)固定,所以即使我不需要某些字段,也一樣需要加載這些字段。
      OK,有的同學(xué)已經(jīng)看出來了。額外定義一個(gè)視圖的實(shí)體對(duì)象即可。定義這些視圖的實(shí)體對(duì)象的確很麻煩,但是肯定比構(gòu)造那些SQL并不斷地維護(hù)它簡(jiǎn)單得多。
      當(dāng)一張表中有1000萬行數(shù)據(jù)時(shí),實(shí)例化1000萬個(gè)對(duì)象是不可能的。
      非常正確。難道你曾經(jīng)成功地嘗試過將1000萬行數(shù)據(jù)加載到某個(gè)DataTable中并且沒有性能問題?從應(yīng)用的角度來說,在一個(gè)模型中包含的實(shí)例數(shù)超過500行就有設(shè)計(jì)不當(dāng)?shù)南右?。我?duì)Google的抱怨是:當(dāng)搜索結(jié)果超過1000個(gè)時(shí)都會(huì)令我抓狂。讓我從1000行數(shù)據(jù)中找出我所需要的某一行,這是開發(fā)人員的思維,并不是用戶的思維。如果能夠在已有的結(jié)果中進(jìn)行二次、三次或者多次進(jìn)一步的篩選,可能更適合絕大多數(shù)人。我為什么不愿意在分頁中花太多的精力,其原因也是如此。我認(rèn)為用戶的眼球只能接受100行以內(nèi)的數(shù)據(jù),超過這個(gè)行數(shù)就需要采用其它的方式,或者改善領(lǐng)域設(shè)計(jì)。所以,這個(gè)問題的答案是:你不可能需要一次載入1000萬行。
      當(dāng)應(yīng)用系統(tǒng)整體性能欠佳時(shí),因?yàn)殡[藏了數(shù)據(jù)訪問細(xì)節(jié),從而無法找到快速優(yōu)化的途徑。
      不能同意。幾乎每一個(gè)ORM框架都提供了非常可靠的數(shù)據(jù)庫訪問日志。通過這些日志分析性能損失將比直接使用SQL語句更可靠、更方便。

      靈活性
      ORM不夠靈活?我完全不能理解,我甚至不知道這個(gè)不夠靈活是與什么基準(zhǔn)相比。相反,ORM可以讓你靈活地替換數(shù)據(jù)庫(當(dāng)然這個(gè)優(yōu)點(diǎn)并沒有非常重要的意義);在修改數(shù)據(jù)庫以后不需要修改服務(wù)層或者只需要進(jìn)行簡(jiǎn)單的修改;可以對(duì)某個(gè)服務(wù)進(jìn)行單獨(dú)的測(cè)試;可以對(duì)服務(wù)進(jìn)行不依賴數(shù)據(jù)庫的、上下文一級(jí)的擴(kuò)展;可以進(jìn)行更好的層次設(shè)計(jì);......
      不能實(shí)現(xiàn)所有的查詢條件
      如果是想表達(dá)“每一個(gè)Select語句可以通過面向?qū)ο蟮姆绞竭M(jìn)行查詢”的話,我覺得目前絕大部分ORM框架都已經(jīng)很好地解決。我解決這一問題的基礎(chǔ)是:我不提供超越SQL ANSI92的能力,但覆蓋SQL ANSI92的所有功能。對(duì)于解決實(shí)際應(yīng)用中的不足部分,采用運(yùn)行時(shí)算法補(bǔ)充。Hibernate采用的是HQL這樣的方式,基本上SQL能夠做到的,HQL都無一例外可以做到。ECO采用的是OCL的方式,其功能可以完全覆蓋SQL。我的框架所實(shí)現(xiàn)的查詢目前我還沒有發(fā)現(xiàn)無法解決并必須利用Native SQL來實(shí)現(xiàn)的(因此我無法理解Hibernate3為什么要提供這樣的擴(kuò)展)。Hibernate采用的策略是以面向?qū)ο鬄楹诵?,換句話說,以持久化對(duì)象為終極目標(biāo),而以加載對(duì)象以持久化對(duì)象為前提。設(shè)計(jì)一個(gè)POJO,實(shí)例化,然后保存起來,下次使用的時(shí)候可以依樣載入即可。大規(guī)模的查詢并不是框架的核心目標(biāo)。所以,如果你完全依賴Hibernate去持久化,我非常擔(dān)心你將來是否有機(jī)會(huì)用你的數(shù)據(jù)積累去做數(shù)據(jù)倉庫。而我的框架目標(biāo)則不同。在持久化與加載兩個(gè)目標(biāo)間我沒有主次之分。我也沒有超前到MDA,我的對(duì)象模型仍然基于數(shù)據(jù)庫的ER設(shè)計(jì),我仍然提供一組非常清晰明了的數(shù)據(jù)庫視圖。
      多表連接查詢
      如果需要將多表的連接查詢結(jié)果轉(zhuǎn)換成一個(gè)二維視圖,顯然需要你再定義另一個(gè)視圖實(shí)體對(duì)象,將視圖映射到對(duì)象模型。如果你僅僅是要在一個(gè)對(duì)象實(shí)例的某個(gè)屬性中獲得另外一個(gè)對(duì)象的集合,似乎這不是DAL方式的優(yōu)勢(shì),而反而是ORM的優(yōu)勢(shì)。將多個(gè)對(duì)象所依賴的多個(gè)對(duì)象放到同一個(gè)上下文中,顯然這是最好的一種方式。
      統(tǒng)計(jì)查詢
      從理論上講,ORM不適合做OLAP,不適合做太多統(tǒng)計(jì)查詢。其實(shí)這一點(diǎn),我的框架已經(jīng)提供了非常好的解決方案,對(duì)Aggregate到面向?qū)ο蟮囊晥D處理得非常好。

      開發(fā)效率
      提高開發(fā)效率僅僅是一個(gè)抽象的目標(biāo),具體的手段應(yīng)該是兩個(gè)方面:一是IDE和輔助工具;一是適合將任務(wù)分解成多個(gè)解耦的部分從而可以通過增加人員來提升總的開發(fā)效率。雖然ORM僅僅是開發(fā)環(huán)節(jié)中很小的一部分,但是卻遍布應(yīng)用系統(tǒng)中的每一角落,因而對(duì)開發(fā)效率影響較大。除了ORM,難道還有更好的選擇么?
      ORM后,原來精湛的SQL技能變得毫無用武之地,讓人甚是失落,但這并不是ORM的過錯(cuò)。

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多