DataTable資料檢索的效能分析[轉]

來源:互聯網
上載者:User

標籤:

原文連結 作者寫得非常好,我學到了許多東西,這裡只是轉載!

 

我們知道在.NET平台上有很多種資料存放區,檢索解決方案-ADO.NET Entity Framework,ASP.NET Dynamic Data,XML, NHibernate,LINQ to SQL 等等,但是由於一些原因,如平台限制,比如說必須基於.NET Framework2.0及以下平台;遺留的或者第三方資料介面採用的就是DataTable等等,仍然需要使用DataTable作為資料存放區結構。另一方面DataTable比較容易使用,一些資料訪問的介面可能直接採用了DataTable結構。在使用DataTable進行資料檢索的時候,有一些需要注意的地方,這些地方會嚴重的影響對資料的檢索效率。

    本人最近工作中需要對大量的DataTable進行拼接。介面的資料是以DataSet然后里面放DataTable的方式提供的,暫不提是否合理,同時進行多個請求的時,服務端會返回一個DataSet,其中包含每個請求的結果DataTable,這些DataTable中有一列相當於”關鍵字”列。現在需要按照這個關鍵字,將這些DataTable中的列合并到一個DataTable,然後展現到介面上來。

    最開始,我使用的是DataTable的Select方法來迴圈遍曆拼接實現的,發現很慢,於是總結了一下對DataTable進行查詢等操作的一些經驗,和大家分享。

一  情境

    為了簡化問題,有兩張DataTable,名為表A,表B,欄位分別為

     表A,儲存股票的最高價資訊,        表B儲存股票最低價資訊

     SecurityCode    High                  SecurityCode    Low

     000001.SZ       20                     000001.SZ      18.5

     000002.SZ       26                     000002.SZ       56

    現在需要,將這兩張表拼接到一張表中,這張表有三欄欄位,SecurityCode High Low,之前採用的方法是,建立一張含有這三個欄位的DataTable 表C,然後複製Security欄位,然後遍曆另外兩張表,對其採用Select方法尋找對應的SecurityCode,然後複製給C中對應欄位。發現效率很慢,問題出現在Select方法上,於是需要進行最佳化。

二 DataTable 的查詢效率

    DataTable提供了兩個查詢資料的介面,DataTable.Select和DataTable.Rows.Find方法。

    DataTable的Select方法通過傳入一系列條件,然後返回一個DataRow[ ]類型的資料,他需要遍曆整個表,然後挨個匹配條件,然後返回所有匹配的值。很顯然在策略上,之前的DataTable拼接採用Select方法存在問題,因為我們只需要尋找匹配上的一條記錄即可。

    DataTable.Rows 的Find尋找第一個匹配上的唯一一條記錄。在指定了主鍵的基礎上,尋找會採用二叉樹的方式尋找,效率高。要建立主鍵,需要指定DataTable的PrimaryKey欄位如下:

dtA.PrimaryKey = new DataColumn[] { dtA.Columns["SecurityCode"] };

當然,建立主鍵會增加時間消耗,這也分為在資料填充前建立和資料填充後建立。在資料量大的情況下,建立主鍵的消耗是需要考慮進去的。下面的圖中顯示了在填充資料之前建立主鍵,之後建立主鍵,以及建立Dictionary所需的時間。可以看到:

ArraySize

PreIndex Creation Time

PostIndex Creation Time

Dictionary Creation Time

10

0

0

0

50

0

0

0

100

1

0

0

500

6

1

0

1000

15

2

0

5000

107

16

2

10000

261

42

5

50000

1727

271

31

100000

3525

544

47

500000

20209

2895

240

1000000

43382

5919

517

    作圖如下:

從可以得到:

  1. 在填充資料之前建立主鍵,然後填充資料,比填充資料完之後建立主鍵消耗的時間要多。這是由於,建立主鍵後,再向其中添加資料,會導致需要重建索引,這和資料庫中,不適合在頻繁變動的欄位上建立主鍵的原理是一樣的。在我的筆記本 (Win7 32bit,CPU T6600 2.0GHZ,RAM 2GB)上,為100萬條記錄的DataTable建立索引大約需要5秒鐘,所以在資料量大的情況下,需要考慮索引的建立時間。
  2. 建立DataTable然後建立主鍵與直接建立和該DataTable相同的Dictionary結構相比,建立Dictionary所需要的時間要少的多,而且幾乎不隨著記錄條數規模的變大而變大。

    建立完成之後,下面來測試幾種情況下的DataTable的檢索效率。為此,在建立主鍵和沒有建立索引的條件下,測試了在不同規模下 DataTable.Select, DataTable.Rows.Find 的查詢速度,由於在DataTable比較小的時候,時間不能很好的顯示,所以測試採用的單位是StopWatch的Tick數。每個方法在資料規模不同的情況下,各執行了10次,然後取平均值,結果如下:

ArraySize Dictionary Create Dictionary Search Table Select Indexed Table Select Table Rows Find LINQ
10 13 3 40 25 8 16
50 27 2 69 37 8 27
100 51 3 112 38 9 39
500 210 3 589 51 11 155
1000 461 4 1175 60 14 328
5000 2264 14 8412 85 17 1540
10000 6235 7 16806 99 20 3354
50000 23768 8 150133 138 26 15824
100000 49133 7 259794 147 26 31525
500000 252103 51 1547935 181 30 158317
1000000 494647 9 2736616 209 30 315716

作圖如下:

 

可以看到:

  1. 在沒有建立主鍵的條件下,對DataTable執行Select操作時比較低效的。在建立主鍵之後,僅對主鍵所在列執行Select操作,速度提高了很多,這種差距在資料量大的情況下尤其明顯,在集合大小規模為1000時,該差異達到了近20倍。
  2. LINQ對DataTable的查詢效率比DataTale.Select方法要高,但是仍然比DataTable.Rows.Find方法效率要低。
  3. 在對主鍵進行唯一性尋找時,我們應該使用DataTable.Rows.Find操作,在DataTable建立主鍵,並且僅對主鍵進行操作的情況下,Find方法會比Select方法快3-6倍,這可能是由於Select方法需要對裡面的過濾字串進行解析及判斷。因為Select方法可以接受多個條件的查詢以及以一些比較複雜的運算式,處理及解析可能需要耗費一些時間。並且在一般條件下Select是完全搜尋,即尋找整個集合找到所有滿足條件的記錄。而Find方法則僅對主鍵欄位進行檢索,如果沒有設定主鍵,那麼調用Find方法就會報錯。
  4. 採用Dictionary來代替DataTable結構來進行檢索,能達到最快的速度,且幾乎不受規模的影響,但是在資料量較大的情況下,將DataTable轉換為對應的Dictionary結構可能需要花費時間,如果操作頻繁,諸如在進行多個DataTable基於關鍵字進行拼接的情況下,對目標DataTable使用Dictionary<String,DataRow> 的方式進行儲存,能夠使用ContainsKey的基於Hash的方式對關鍵字進行尋找,這能極大地提高效率。並且在DataTable列有重複欄位,不能建立主鍵的情況下,可以採用Dictionary<string,List<DataRow>>能夠解決DataTable無法建立主鍵,從而導致尋找效能下降的問題。

 

三  實施效果

    基於上面的分析,在實際中的工作中,替換了Select方法,建立了一個類型為Dictionary<String,DataRow>的包含目標合并後DataTable對象的所有行的結構C,其中關鍵字為SecurityCode,DataRow為包含SecurityCode,High,Low三列資料的行。在合并的時候,直接遍曆表A的所有行,然後判斷在C中是否包含該行中的SecurityCode,如果包含,取出,直接賦值。然後遍曆表B。整個過程使得DataTable合并的效率至少提高了10倍。

四  結語

    本文簡要介紹了DataTable中檢索資料的兩種方法,DataTable.Select 和DataTable.Rows.Find方法。在測試方法的執行效率之前介紹了如何為DataTable設定主鍵,並比較了在資料填充之前和資料填充之後設定主鍵花費的時間,結果表明,在資料填充完成之後,設定主鍵要比在填充資料之前設定主鍵效率要高的多。設定主鍵之後,比較了在有無主鍵的情況下,DataTable.Select 方法在僅對主鍵欄位進行過濾時的效能,結果表明,在僅對主鍵進行檢索時,設定主鍵之後使用DataTable.Select 方法會比沒有主鍵的情況下的檢索速度會快非常多。在相同條件下,如果僅需要尋找某一條記錄,使用DataTable.Rows.Find會比DataTable.Select快很多。在某些需要頻繁操作DataTable查詢的時候,要避免在迴圈體內調用DataTable.Select方法,採用將DataTable轉換為等價的Dictionary結構,能夠有效解決由於索引值重複導致不能建立主鍵的問題並且Dicitonary的採用雜湊表的方式尋找能夠極大地提高查詢效率。

 

DataTable資料檢索的效能分析[轉]

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.