c# - groupby - linq语法




LINQ是否使用DataRelations来优化连接? (2)

在Reflector中进行挖掘似乎没有给出LINQ使用DataRelations的任何迹象,但该代码非常难以阅读。 所以我写了一个小小的性能测试,除非我错过了测试,否则结果是非常明确的:不,LINQ不使用DataRelations和GetChildRows()来投影连接的行。 如果你想迭代子行,你必须制定LINQ查询来显式地调用GetChildRows()。 而且这两种方法都不如编写迭代GetChildRows()返回的数组的代码。

不幸的是,因为大型数据集的性能差异足够大,用显式实现的代码取代LINQ往往是值得的,而LINQ通常不是这样。

我的测试代码如下。 无论DataRelation是在其之前还是之后创建的,使用连接的LINQ迭代的时间保持不变(我的机器上大约为580-590毫秒)。 使用GetChildRows()的LINQ迭代需要大约280毫秒,

直接通过GetChildRows()的迭代需要毫秒。 这对我来说真是令人惊讶 - 足够让我假设我在第一次运行测试时在代码中出现了一个错误。 (这就是为什么我每次写出计数的原因 - 确保编译器没有对循环进行优化。)

class Program
{
    static void Main(string[] args)
    {
        Stopwatch sw = new Stopwatch();
        DataSet ds = new DataSet();
        DataTable t1 = new DataTable();
        t1.Columns.Add(new DataColumn
                           {
                               ColumnName = "ID",
                               DataType = typeof (int),
                               AutoIncrement = true
                           });
        t1.PrimaryKey = new [] { t1.Columns["ID"]};
        ds.Tables.Add(t1);

        DataTable t2 = new DataTable();
        t2.Columns.Add(new DataColumn
        {
            ColumnName = "ID",
            DataType = typeof(int),
            AutoIncrement = true
        });
        t2.Columns.Add("ParentID", typeof(int));
        t2.PrimaryKey = new[] { t2.Columns["ID"] };
        ds.Tables.Add(t2);

        sw.Reset();
        sw.Start();
        PopulateTables(t1, t2);
        sw.Stop();
        Console.WriteLine("Populating tables took {0} ms.", sw.ElapsedMilliseconds);
        Console.WriteLine();

        var list1 = from r1 in t1.AsEnumerable()
                   join r2 in t2.AsEnumerable()
                       on r1.Field<int>("ID") equals r2.Field<int>("ParentID")
                   where r1.Field<int>("ID") == 1
                   select r2;

        sw.Reset();
        sw.Start();
        int count = 0;
        foreach (DataRow r in list1)
        {
            count += r.Field<int>("ID");
        }
        sw.Stop();
        Console.WriteLine("count = {0}.", count);
        Console.WriteLine("Completed LINQ iteration in {0} ms.", sw.ElapsedMilliseconds);
        Console.WriteLine();

        sw.Reset();
        sw.Start();
        ds.Relations.Add(new DataRelation("FK_t2_t1", t1.Columns["ID"], t2.Columns["ParentID"]));
        sw.Stop();
        Console.WriteLine("Creating DataRelation took {0} ms.", sw.ElapsedMilliseconds);

        sw.Reset();
        sw.Start();
        var list2 =
            from r1 in t1.AsEnumerable()
            from r2 in r1.GetChildRows("FK_t2_t1")
            where r1.Field<int>("ID") == 1
            select r2;

        count = 0;
        foreach (DataRow r in list2)
        {
            count += r.Field<int>("ID");
        }
        sw.Stop();
        Console.WriteLine("count = {0}.", count);
        Console.WriteLine("Completed LINQ iteration using nested query in {0} ms.", sw.ElapsedMilliseconds);
        Console.WriteLine();

        sw.Reset();
        sw.Start();
        DataRow parentRow = t1.Select("ID = 1")[0];
        count = 0;
        foreach (DataRow r in parentRow.GetChildRows("FK_t2_t1"))
        {
            count += r.Field<int>("ID");
        }
        sw.Stop();
        Console.WriteLine("count = {0}.", count);
        Console.WriteLine("Completed explicit iteration of child rows in {0} ms.", sw.ElapsedMilliseconds);
        Console.WriteLine();

        Console.ReadLine();
    }

    private static void PopulateTables(DataTable t1, DataTable t2)
    {
        for (int count1 = 0; count1 < 1000; count1++)
        {
            DataRow r1 = t1.NewRow();
            t1.Rows.Add(r1);
            for (int count2 = 0; count2 < 1000; count2++)
            {
                DataRow r2 = t2.NewRow();
                r2["ParentID"] = r1["ID"];
                t2.Rows.Add(r2);
            }
        }
    }
} 

我找不到任何地方的答案,并且在我用Reflector开始生成代码之前,我认为这是值得问的:

假设我有一个DataSet中的DataTables运行下面的LINQ查询:

var list = 
   from pr in parentTable.AsEnumerable()
   join cr in childTable.AsEnumerable() on cr.Field<int>("ParentID") equals pr.Field<int>("ID")
   where pr.Field<string>("Value") == "foo"
   select cr;

如果父表和使用显示的关键字段的子表之间有一个DataRelation,LINQ会使用它吗? 也就是说,它会在父表中找到Value为“foo”的行,然后调用GetChildRows来投影子行?

或者这是我必须明确指定的东西? (如果是这样,我该怎么做?)


我不这么认为。 在这种情况下,LINQ to Objects可能只是将双方视为常规的可枚举对象,并手动进行连接(不需要查看DataRelation )。





datarelation