Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/74.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 高效地加入内存中的列表_C#_Sql_Performance_Linq_Entity Framework - Fatal编程技术网

C# 高效地加入内存中的列表

C# 高效地加入内存中的列表,c#,sql,performance,linq,entity-framework,C#,Sql,Performance,Linq,Entity Framework,在EF中,如果我有一个灵长类动物列表,将其与一个表连接起来很容易: var ids = int[]{1,4,6}; //some random values var rows = context.SomeTable.Where(r => ids.Contains(r.id)) 当您想要连接多个列时,这会变得更加复杂: var keys = something.Select(s => new { s.Field1, s.Field2 }) var rows = context.Som

在EF中,如果我有一个灵长类动物列表,将其与一个表连接起来很容易:

var ids = int[]{1,4,6}; //some random values
var rows = context.SomeTable.Where(r => ids.Contains(r.id))
当您想要连接多个列时,这会变得更加复杂:

var keys = something.Select(s => new { s.Field1, s.Field2 })
var rows = context.SomeTable.Where(r => keys.Contains(r => new { s.Field1, s.Field2 })); // this won't work
我找到了两种加入的方式,但都不是很好:

吸入整个表,并根据其他数据对其进行过滤。如果桌子真的很大,速度就会变慢 对于每个键,查询表。如果有足够多的行要拉入,那么查询速度会变慢 有时,我能做的折衷是修改1:基于一个相当唯一的键拉入表的子集

var keys = something.Select(s => s.Field1)
var rows = context.SomeTable.Where(r => keys.Contains(s.Field1)).ToList();
foreach (var sRow in something)
{
    var joinResult = rows.Where(r => r.Field1 == sRow.Field1 && r.Field2 == sRow.Field2);
    //do stuff
}
但即便如此,也可能收回太多数据


我知道有很多方法可以将表值参数引入ADO.Net,也有一些方法可以将一系列.Where子句组合在一起。有人有魔法子弹吗?

你可以试着将你的钥匙压平,然后使用相同的图案。虽然可以使用函数索引将展平键存储在数据库中,但这在大型查询中可能不会执行得很好

我有一个表Test,列K1 int,K2 int,名称varchar50

不幸的是,我没有EF在这台笔记本电脑上,甚至不能测试这是否是语法正确


我也不知道它的性能如何,如果它能工作的话…

而不是.Contains,那么使用一个内部连接和过滤器怎么样:

from s in context.SomeTable
join k in keys on new {k.Field1, k.Field2} equals new {s.Field1, s.Field2}
上面可能有输入错误,但你知道

var rows = 
from key in keys
join thingy in context.SomeTable
on 1 = 1
where thingy.Field1 == key && thingy.Field2 == key
select thingy

应该可以工作,并生成合理的SQL

我遇到了完全相同的问题,我提出的解决方案是:

朴素:对每个本地记录执行单独的查询 更聪明:创建两个唯一Filed1值和唯一Fiels2值的列表,使用2个contains表达式进行查询,然后您将不得不对结果进行双重筛选,因为它们可能不太准确。 看起来像这样:

 var unique1 = something.Select(x => x.Field1).Distinct().ToList();
 var unique2 = something.Select(x => x.Field2).Distinct().ToList();
 var priceData = rows.Where(x => unique1.Contains(x.Field1) && unique2.Contains(x.Field2));
下一个是我自己的解决方案,我称之为BulkSelect,其背后的想法如下:

 var unique1 = something.Select(x => x.Field1).Distinct().ToList();
 var unique2 = something.Select(x => x.Field2).Distinct().ToList();
 var priceData = rows.Where(x => unique1.Contains(x.Field1) && unique2.Contains(x.Field2));
使用直接SQL命令创建临时表 将SELECT命令的数据上载到该临时表 拦截并修改EF生成的SQL。
我是为博士后做的,但这可能需要移植到MSSQL。这一点描述得很好,源代码是

。为了提高性能,请使用context.ExecuteQuery发送定制的SQL语句。我认为它不会起作用,因为在本例中,键是匿名对象的集合,而不是int、string、Guid、DateTime等基元类型。。它很可能会抛出臭名昭著的“无法创建xyz类型的常量值”。仅支持基本类型。。。异常。@Slauma刚刚在Linqpad中运行了一个更简单的示例,我很确定您是对的。除非我记错了,否则这用于生成SELECT。。。来自没有where子句的某个表。当我在该表中有1000多万行时,这很糟糕。我没有尝试1=1,但我会假设它会在该点加载整个SomeTable查询生成器会考虑整个查询,包括where子句,并且只在必须时(即在枚举结果时)才会进入数据存储,这可能更晚,在一堆其他查询表达式之后。我会说试试看,看看它会把你带到哪里。如果生成的SQL很糟糕,您可以随时决定不使用它。在联接的左侧设置内存中的数据不是一个好的做法。您应该颠倒顺序,始终将DbSet数据放在左侧,内存中的数据放在右侧。看见
 var unique1 = something.Select(x => x.Field1).Distinct().ToList();
 var unique2 = something.Select(x => x.Field2).Distinct().ToList();
 var priceData = rows.Where(x => unique1.Contains(x.Field1) && unique2.Contains(x.Field2));