例如,我有10000000条记录的表格,并在内存中列出 ,包含100000个ID。
如何通过这些ID选择所有记录? 显然,我可以这样做:
var ids = GetIds();
var result = from q in ctx.Records
where ids.Contains(q.Id)
select q;
但如果我这样做,会有两个问题:
每次使用此查询时生成的SQL都会出现怪异。
每行的O(N)复杂性。所以,我会在几年后收到我的结果。
我怎么能这样做?如何用linq2sql
完成,或者这是不可能绕过的?
更新
是的,我测试了它,我调试了它并且已经看到了生成的内容。它是这样的:
SELECT * FROM Records WHERE id IN (/*one hundreds of thousand goes here O_O*/)
简单数学:10.000.000 x 100.000将给出1.000.000.000.000的时间复杂度。这非常低效。
答案 0 :(得分:1)
正如你所说,在内存中进行这些操作并不好。解决方案是在数据库中有另一个表,然后您的代码将是:
var ids = GetIds();
//Insert all ids into database (bulk insert)
var result = from q in ctx.Records
join i in ctx.Ids on q.Id equals i.Id
select q;
这样操作将在数据库中进行,您将克服in
子句中项目数量的限制。
id
的{{1}}字段应该有索引(或者如果它是主键,它也已被索引)Records
表的id字段也应编入索引这种方式的联接将是Ids
而不是Hash join
- 相当于使用Nested Join
集合作为ids
而不是{{}的.Net解决方案{1}}。
最后,要同时支持多项操作,您可以让HashSet<string>
包含2列:List<string>
,Ids
。 Id
将被提供给特定插入内容的所有OperationId
,然后您的查询将如下所示:
OperationId
_确保Id
也被编入索引 - 可以是var result = from q in ctx.Records
join i in ctx.Ids on q.Id equals i.Id
where i.OperationId = _the operationId given by the insert_
select q;
的相同索引,但请注意它是第一个。
根据DBMS,您还可以将您的表格设置为OperationId
- 至少对于Oracle,它会在每个连接的会话中存储数据 - 因此您可以一次插入多个会话但数据不是共享 - 因此您不需要Id