使用LINQ to Entities多次枚举大型数据集

时间:2014-01-10 20:14:01

标签: c# sql linq entity-framework

假设我的SQL数据库中有两个表。 1.一张中等大小的表,有数千条名为MyTable1的记录 2.一张包含数百万条记录(并且日益增长)的大型表格,名为MyTable2

MyTable1和MyTable2都有一个名为Hash的属性,可以是相同的。

我希望找到最有效的方法来使用Linq to Entities迭代MyTable1并找到MyTable2中具有相同Hash并保存到另一个表中的所有记录。以下是代码外观的简化视图。

using(var db = new context()) {
    var myTable1Records = db.MyTable1.Select(x => x);

    foreach(var record in myTable1Records) {  
        var matches = db.MyTable2.Where(y => y.Hash.Equals(record.Hash)).Select(y => y);
        foreach(var match in matches) {
           // Add match to another table
        }
    }
}

随着MyTable2的大小每天都在变大,我看到这段代码的性能显着下降。我正在尝试有效处理这种情况的一些想法是:

  1. 在db.MyTable2上设置MergeOption.NoTracking,因为它纯粹是一个读取操作。不幸的是,没有看到很多改进。
  2. 使用.ToList()将MyTable2拉入内存以消除对db的多次调用
  3. 创建MyTable2的“块”,代码可以迭代,因此每次都不会查询全部的百万条记录。
  4. 我很想知道在这种情况下你是否有其他技术或魔法子弹有效。谢谢!

4 个答案:

答案 0 :(得分:1)

您有一个名为Hash的媒体资源。使用它作为哈希!将第一个表存储在由Dictionary键入的Hash中,然后遍历第二个表格,检查Dictionary中的匹配项,再次按Hash键入。

或者,更好的是,使用LINQ:

var matches = db.MyTable1.Intersect(db.MyTable2);

如果您需要进行自定义比较,请创建IEqualityComparer。 (我假设您正在进行某种类型的投影,Select(x => x)是占位符,用于此问题。)

或者,更好的是,在存储过程或视图中完全在数据库中进行此操作可能会更好。你基本上是做JOIN但是用C#来做。您需要承担从数据库到客户端应用程序的往返时间成本,以便在数据库服务器上完成所有操作。

答案 1 :(得分:1)

你在这里做的是执行内连接。通过使用查询提供程序,您甚至可以确保此工作在数据库端完成,而不是在应用程序的内存中完成;你只会拉下匹配的结果,不再:

var query = from first in db.MyTable1
    join second in db.MyTable2
    on first.Hash equals second.Hash
    select second;

答案 2 :(得分:1)

答案 3 :(得分:1)

可能索引你的哈希列可以提供帮助。假设Hash是char或varchar类型,索引可以支持的最大长度为900字节。

CREATE NONCLUSTERED INDEX IX_MyTable2_Hash ON dbo.MyTable2(Hash);

对于索引varchar的性能,您可能需要在此处查看 SQL indexing on varchar