6,ORM組件XCode(撬動千萬級數據)

    有了前面的《動手》,基本上能夠進行開發了。本篇咱們來試試XCode的基本功功力如何,測試在單表一千萬業務數據的環境下查詢的速度,添刪改等沒什麼可測試的。其實應該說是XCode開發模式的功力,XCode組件僅僅是處理分頁而已,而XCode開發模式爲高性能開發提供了更多的建議。 html

    測試環境:雙核CPU,4G內存,win7+SQL2008+vs2010 sql

    數據表字段包括:自增ID、車牌、時間。使用SQL準備一千萬測試數據,花了將近一個小時。 數據庫

    測試用例:ID的升序降序,時間的升序降序,每一種狀況測試取首頁、中間頁、尾頁的時間。 架構

    XCode開發模式很是看重分頁,基本上全部集合查詢方法都帶有分頁參數。Entity層只負責生成獲取知足條件的全部數據的SQL,加上分頁參數後傳遞給下層數據訪問層,自身不處理問題。數據訪問層調用IDatabase接口的PageSplit方法,把上述的SQL處理爲只獲取指定頁的SQL,而後再執行查詢操做。由於不一樣的數據庫分頁方法不一樣,因此XCode的這種架構讓使用者無需關心採用哪種分頁方法。測試環境是SQL2008,因此自動採用row_number分頁。 ide

 

    首先創建數據表 工具

代碼
CREATE   TABLE   [ dbo ] . [ test ] (
    
[ ID ]   [ int ]   IDENTITY ( 1 , 1 NOT   NULL ,
    
[ HPHM ]   [ varchar ] ( 50 NULL ,
    
[ JGSJ ]   [ datetime ]   NOT   NULL ,
 
CONSTRAINT   [ PK_CLTXJL ]   PRIMARY   KEY   CLUSTERED  
(
    
[ ID ]   DESC
)
WITH  (PAD_INDEX   =   OFF , STATISTICS_NORECOMPUTE   =   OFF , IGNORE_DUP_KEY  =   OFF , ALLOW_ROW_LOCKS   =   ON , ALLOW_PAGE_LOCKS   =   ON ON   [ PRIMARY ]
ON   [ PRIMARY ]

 

     使用SQL語句插入一千萬行數據 性能

declare   @i   int
set   @i = 0
while   @i < 100
begin
insert   into  test  values ( ' 鄂A94450 ' , getdate ())
insert   into  test  values ( ' 鄂A92355 ' , getdate ())
(這裏是更多數據插入語句)
set   @i = @i + 1
end
GO

 

    最後是這種樣子 測試

wps_clip_image-18008

    再看看咱們準備的測試代碼 網站

測試代碼
static   void  Test2()
{
    Stopwatch sw 
=   new  Stopwatch();
    sw.Start();

    Console.WriteLine();
    DAL.AddConnStr(
" Center " " Data Source=.;Initial Catalog=Center;User ID=sa;Password=Pass@word " null " sql2008 " );
    IEntityOperate factory 
=  DAL.Create( " Center " ).CreateOperate( " test " );
    sw.Stop();
    Console.WriteLine(
" 初始化:{0} " , sw.Elapsed);

    ICollection list 
=  factory.FindAll( null null null 100000 1 );
    DateTime dt 
=  DateTime.Now;
    
foreach  (IEntity item  in  list)
    {
        dt 
=  (DateTime)item[ " JGSJ " ];
        
break ;
    }

    
// String where = String.Format("{0}>='{1}' And {0}<'{2}'", "JGSJ", dt, dt.AddSeconds(100));
    String  where   =  String.Empty;

    sw.Reset();
    sw.Start();
    Console.WriteLine();
    Int32 count 
=  factory.FindCount( where null null 0 0 );
    sw.Stop();
    Console.WriteLine(
" 查詢總記錄數:{0} " , sw.Elapsed);
    Console.WriteLine(
" 總記錄數:{0} " , count);

    Test2_0(sw, 
" 默認順序 " , count,  where null );
    Test2_0(sw, 
" 時間升序 " , count,  where " JGSJ Asc " );
    Test2_0(sw, 
" 時間降序 " , count,  where " JGSJ Desc " );
}

///  
///  測試用例
///  
///   計時器
///   標題
///   總記錄數
///   條件字句
///   排序字句
static   void  Test2_0(Stopwatch sw, String title, Int32 count, String  where , String order)
{
    Console.WriteLine();
    Console.WriteLine(
" {0}: " , title);

    IEntityOperate factory 
=  DAL.Create( " Center " ).CreateOperate( " test " );

    sw.Reset();
    sw.Start();
    Console.WriteLine();
    ICollection list 
=  factory.FindAll( where , order,  null 0 10 );
    sw.Stop();
    Console.WriteLine(
" 查詢前10行:{0} " , sw.Elapsed);

    sw.Reset();
    sw.Start();
    Console.WriteLine();
    list 
=  factory.FindAll( where , order,  null , count  /   2 10 );
    sw.Stop();
    Console.WriteLine(
" 中間10行({1}):{0} " , sw.Elapsed, count  /   2 );

    sw.Reset();
    sw.Start();
    Console.WriteLine();
    list 
=  factory.FindAll( where , order,  null , count  -   10 10 );
    sw.Stop();
    Console.WriteLine(
" 最後10行({1}):{0} " , sw.Elapsed, count  -   10 );
}

 

    上面第一個方法是控制方法,用來控制測試用例的。第二個方法就是測試用例了。 spa

    在這裏不得不提的是,第一個方法使用了最新版本V5.0的新特性——弱類型訪問。上一篇《動手》中提到,使用XCode首先須要利用代碼生成器生成實體類代碼,或者手工編寫,反正是須要實體類代碼,而本文只是爲了測試,不須要那麼複雜。動態添加一個鏈接字符串Center,並建立數據表test的操做接口,後面就能夠利用這個操做接口去查詢數據了。弱類型訪問這一塊後面會專門介紹。

    第二個方法有三次查詢,分別是首頁、中間頁和尾頁。

    先來看看「默認順序」,其實就是ID降序

wps_clip_image-27189

    由於數據表默認爲自增ID創建彙集索引,因此在ID字段上的分頁查詢是最快的,首頁才3毫秒,中間頁也才4.5秒。

這裏有必要說一下尾頁,這裏不是做弊,而是XCode的一個小手段。在實際應用分頁查詢的時候,每每是越日後越慢,但只要把數據倒過來查,ID降序的尾頁其實就是ID升序的首頁,結果行集一致,只不過這10行數據是倒過來的,XCode在最後返回實體集合的時候會把它倒過來,就成了ID降序了。因此,在XCode查詢中,中間頁之後的頁都是反向查詢,中間頁是最慢的。

    接着看看「時間升序」

wps_clip_image-27635

    首頁和尾頁5秒,中間頁17秒,很糟糕!看一下它們的執行計劃
wps_clip_image-31722
wps_clip_image-13542
wps_clip_image-5627

    習慣性的先看總開銷,三條語句竟然是勢均力敵,執行時間一致!這個我就沒法解釋了。

    從執行計劃能夠看到,95%的開銷都在於排序

wps_clip_image-14991

    看詳情,原來是對JGSJ的排序形成的。看來應該爲JGSJ創建索引。

    最後的這個「時間降序」,時間跟「時間升序」差很少,原理也同樣,就不分析了。

wps_clip_image-29070

    上次第一輪測試看到,沒有索引,實在杯具!下面咱們給JGSJ字段加上索引,繼續測試

wps_clip_image-10701

wps_clip_image-18189

wps_clip_image-17478

    有了明顯變化,首頁和尾頁足夠快了,中間頁也變快了,可是仍是偏慢,怎麼回事?從執行計劃看到,99%的時間都在於鍵查找

wps_clip_image-6367

    原來是查找對應的HPHM,也是,索引只負責時間字段,而HPHM字段仍是須要作全表掃描找出來的。在索引裏面包含它試試

CREATE   NONCLUSTERED   INDEX  IX_test_1  ON  dbo.test
(
  JGSJ
)
include (HPHM)
WITH ( STATISTICS_NORECOMPUTE  =   OFF , IGNORE_DUP_KEY  =   OFF , ALLOW_ROW_LOCKS  =   ON , ALLOW_PAGE_LOCKS  =   ON ON   [ PRIMARY ]

 

wps_clip_image-5301

    再次測試

wps_clip_image-22784

    漂亮!結果跟ID自增字段同樣。

    綜合上面的測試,最慢的中間頁能保持在5秒之內,算是一個不錯的成績了。不過這不能徹底算是XCode的功勞,XCode僅僅是生成了分頁語句而已。而創建索引的建議,則是XCode開發模式的範疇。

 

    XCode開發模式建議:每一個表使用自增ID做爲主鍵,獨享彙集索引。在數據分頁上,沒有比自增ID加上彙集索引更快的了,因此要把最好的留給它。業務主鍵還有常常查詢的字段,根據狀況創建非彙集索引。在千萬數據下,沒有索引的字段,基本上查不動。

    創建索引時,特別注意包含字段include(不是組合索引)。好比爲時間字段創建了索引,根據時間字段查詢的時候,掃描索引字段會很快,可是掃描以後絕大部分時間都花在查找時間字段對應的車牌字段上了,若是創建時間字段索引的時候,把車牌字段include進去,就至關於在索引目錄裏面就擁有了車牌信息,直接省去了對應車牌這一步,查詢性能將會獲得很是大的提升。固然,include也是有代價的,添刪改操做會比原來慢,而且要佔用更大的存儲空間。不過如今硬盤那麼便宜,存儲空間問題不會太大,至於添刪改操做慢多少,就看業務來衡量了,通常能夠接受。

    在SQLServer管理工具裏面創建索引時,彷佛沒法添加include字段。能夠先設置好索引,不要保存,點擊生成腳本,而後複製到查詢窗口,增長include後再執行。

 

    前面的測試,都是簡單的沒有查詢條件的測試,下面咱們試試帶查詢條件的測試

wps_clip_image-13996

    屏幕一閃而過,就這樣完了!圖中看到,符合條件的數據共有2317+10=2327條,在這麼小的數據量裏進行分頁查詢,那速度,天然沒得說!

    在實際應用中,不多有須要查詢那麼多頁的,百度、谷歌和淘寶等大型網站,最多也就返回前面一百頁。而且,業務系統通常有不少查詢條件,好比時間段等,通過這些條件過濾,即便是千萬數據的表,也不會有太多知足條件的數據

 

這一切,XCode已經爲你準備!

 

大石頭

新生命開發團隊

2010-09-07 03:57

 

組件文檔打包下載(1~6)

做者: 大石頭 發表於 2010-09-15 23:28 原文連接

評論: 23 查看評論 發表評論

最新新聞:
· 是否該讓開發人員跟客戶直接交流?(2010-12-21 07:53)
· 亞馬遜副總裁跳槽Groupon任CFO(2010-12-21 07:50)
· Gmail語音服務將延長至2011年末(2010-12-21 07:49)
· AOL收購我的檔案網站About.me(2010-12-21 07:48)
· AT&T 19.25億美圓購入高通 700MHz 低頻頻譜(2010-12-21 07:42)

編輯推薦:Mono又更新了

網站導航:博客園首頁  個人園子  新聞  閃存  小組  博問  知識庫

相關文章
相關標籤/搜索