2015-02-23 33 views
0

問題:我有數百萬行數據庫需要處理。從SqlDataReader返回延期數據

我需要實現一個方法,該方法將返回數據庫行的「流」(?)。 我不想一次將它們全部加載到內存中。

我正在考慮返回一個懶惰的IEnumerable<Record>並使用yield。 該方法將處理使用SqlDataReader加載連續記錄。

但是,如果客戶在我的IEnumerable上撥打.Count(),會發生什麼?計算所有記錄意味着需要將它們全部取出。

有沒有什麼好的現代方法來返回一個對象流,而不是將它們全部存儲在內存中,只是一個一個的處理?我的方法應該返回一個記錄流。

似乎Reactive Extensions可能會爲我解決問題,但我從未使用它。

任何想法?

謝謝

回答

0

對於計數查詢分貝,並返回給用戶。

另一方面,您只需要爲ICollection實現計數,IEnumerable不需要這樣做。只需在記錄上返回IEnumerable進行迭代。

只是注意到你正確處理與db的連接。

2

首先,爲什麼要重新發明輪子?實體框架使得更容易做這樣的事情,併爲您添加所有的抽象。在DbContext物體上的DbSet<TEntity>實現IQueryable<TEntity>IEnumerable<T>這樣你就可以:

  • 執行一個Count()(使用和不使用的λ濾波器參數)與一個擴展方法時,需要弄清楚的記錄數(或一些其他聚合函數)
  • 您可以通過IEnumerable循環它們,每次從連接調用MoveNext方法時,它都會打開一個連接並每次讀取一條記錄。
  • 如果你確實想要一次加載所有內存(我理解你不基於你的描述),你可以調用擴展方法ToList或ToArray。

如果你堅持使用ADO.NET和手動這樣做(我與遺留代碼的理解有不總是使用EF選擇),然後從打開的連接數據讀取器是最好的辦法。這將在每個下一個記錄中讀取每個相應的方法Read()的調用,這是在數據庫中讀取記錄的最便宜的方法。

如果你想有一個伯爵那麼我建議你寫一個返回

SELECT COUNT(field) FROM table 

使用SQL類似於數據庫服務器上執行的數量,因爲這是最好的做法一個新的SQL查詢。不要通過一些自定義工作來迭代和總結讀者的所有記錄,以便在內存中執行總和,這會浪費資源,更不用說創建複雜的代碼而沒有任何好處。

+0

我可能是錯的,但我已經讀過,它只是在EF 6中,他們最終添加了默認打開底層datareader的功能。我測試了EF 5與數據讀取器的性能,當從100萬張的表中拉出50 k行時,數據讀取器的性能提高了33%。 EF 6與數據讀取器的時間幾乎完全相同。 – NightOwl888 2015-02-23 20:00:36

+0

@ NightOwl888 - 有趣。我們仍然有一個使用EF5的遺留應用程序,但除此之外,我對此版本沒有太多的瞭解。我試過尋找,但所有我能找到的是,框架的初始加載時間在版本之間得到了改進。如果你找到一個鏈接,我會有興趣瞭解更多。 ?這也可能是由於EF6生成了更高效的查詢? – Igor 2015-02-23 20:05:31