【问题标题】:What is the most effecient way to pull thousands of records with hundreds of thousands of child records into class objects?将具有数十万子记录的数千条记录拉入类对象的最有效方法是什么?
【发布时间】:2010-12-08 16:45:14
【问题描述】:

我有一个场景,我需要提取大约 7500 条数据库记录,其中每条记录有 6 个子实体列表。这些子列表中的每一个都可以是 0 到大约 125 条记录。

我的班级结构是这样的:

public class Entity
{
    public int ID { get; set;
    public string Name { get; set; }
    public ICollection<ChildEntity1> Children1 { get; set; }
    public ICollection<ChildEntity2> Children2 { get; set; }
    public ICollection<ChildEntity3> Children3 { get; set; }
    public ICollection<ChildEntity4> Children4 { get; set; }
    ... 2 more collections
}

检索所有实体后,我需要遍历每个实体并执行一些计算,调用一些 Web 服务和其他各种事物并最终导出到文件。

使用 c# 4 从 MS Sql Server 2008 检索此数据的最佳策略是什么?带有 DataAdapters 的 DataSet 是最好的方法吗? ORM?

出于显而易见的原因,我想远离选定的 N+1 个场景。

【问题讨论】:

  • 您是否需要同时使用内存中的所有实体,或者您可以获取实体的子集,处理它们,然后将它们写入文件?
  • 一方面,您的策略不应该是“检索所有实体”,然后是“迭代每个实体”。您的算法不能在运行时运行,一次一行,是否有原因?
  • @Gilbert- 可以一次获取一个子集,比如 100 个,处理并添加到最后导出的列表中。父实体及其子实体是完全原子的。
  • @Kirk - 随时随地工作需要我访问数据库约 45000 次(7500 个父记录 * 6 个子集合)。我想这就是我的问题的重点,有没有更有效的方法?
  • @Chris,我不是这个意思。例如,如果您只是使用 ADO.NET 并返回一个 IDataReader,则您为每一行调用 Read 方法。这仅涉及对数据库的一次命中,但不会将整个数据集读入内存。

标签: sql-server-2008 c#-4.0 data-access


【解决方案1】:
DECLARE CURSOR on the Entity.

OPEN CURSOR.

For each FETCH CURSOR

    SELECT the child rows for the current Entity.

    Write the output.

CLOSE CURSOR.

【讨论】:

    【解决方案2】:

    所以我最终做的是有一个嵌套的 DataReader,一个用于父实体获取所有父实体的外部数据读取器,然后一个使用 reader.NextResult() 在一个语句中读取所有子实体的内部数据读取器类似这样的方法:

    var exampleSql = "select * from child1Table; " +
                     "select * from child2Table; " +
                     "select * from child3Table"; 
                     // and so on for the other child tables
    using (var outerReader = cmd.ExecuteReader())
    {
        while (outerReader.Read())
        {
            var entity = new Entity();
            entity.Prop1 = outerReader[0];
            entity.Prop2 = outerReader[1];
            //.... etc.
    
            using (var cmdInner = new SqlCommand(exampleSql))
            using (var innerReader = cmdInner.ExecuteReader())
            {
                while (innerReader.Read())
                {
                    var child = new Child1();
                    child.Prop1 = innerReader[0];
                    // ... etc.
                    entity.Children1.Add(child);
                }
                innerReader.NextResult();
                while (innerReader.Read())
                {
                    var child = new Child2();
                    child.Prop1 = innerReader[0];
                    // ... etc.
                    entity.Children2.Add(child);
                }
                innerReader.NextResult();
                // and so on for the other child entities
            }
        }
    }
    

    至少这样,我只向数据库发送一个 sql 语句来检索每个父级的所有子实体,而不是每个父级每个子级的单独语句。

    如果有人有更好的方法,随时告诉我。

    顺便说一句,我的示例代码只是伪代码。真正的事情是使用参数化查询并且没有选择星,只是我需要的列。目的是展示方法,而不是实际的实现。

    【讨论】:

      猜你喜欢
      • 2015-04-04
      • 2010-10-25
      • 2010-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多