gpt4 book ai didi

c# - LINQ 是否使用 DataRelations 来优化联接?

转载 作者:太空狗 更新时间:2023-10-29 21:37:20 26 4
gpt4 key购买 nike

我无法在任何地方找到这个问题的答案,在我开始使用 Reflector 浏览生成的代码之前,我认为这值得一问:

假设我对数据集中的数据表运行了以下 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 会使用它吗?也就是说,它会在父表中找到值为“foo”的行,然后调用GetChildRows 投影子行吗?

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

最佳答案

深入研究 Reflector 似乎没有任何迹象表明 LINQ 使用 DataRelations,但该代码非常难以阅读。所以我写了一个小的性能测试,除非我错过了一些愚蠢的测试,否则结果是非常确定的:不,LINQ 不使用 DataRelations 和 GetChildRows() 来投影连接的行。如果要遍历子行,则必须制定 LINQ 查询以显式调用 GetChildRows()。这两种方法的性能都不如编写迭代 GetChildRows() 返回的数组的代码。

有点不幸,因为大型数据集上的性能差异非常显着,以至于用显式实现的代码替换 LINQ 通常是值得的,而 LINQ 通常不是这样。

我的测试代码如下。使用连接的 LINQ 迭代的时间保持不变(在我的机器上大约 580-590 毫秒),无论 DataRelation 是在它之前还是之后创建的。使用 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);
}
}
}
}

关于c# - LINQ 是否使用 DataRelations 来优化联接?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/387772/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com