使用 Contains() 时达到 2100 参数限制 (SQL Server)
Posted
技术标签:
【中文标题】使用 Contains() 时达到 2100 参数限制 (SQL Server)【英文标题】:Hitting the 2100 parameter limit (SQL Server) when using Contains() 【发布时间】:2009-03-17 21:47:16 【问题描述】:from f in CUSTOMERS
where depts.Contains(f.DEPT_ID)
select f.NAME
depts
是部门 ID 列表 (IEnumerable<int>
)
这个查询工作正常,直到你传递一个大列表(比如大约 3000 个部门 ID).. 然后我得到这个错误:
传入的表格数据流 (TDS) 远程过程调用 (RPC) 协议流不正确。此 RPC 请求中提供的参数过多。最大值为 2100。
我将查询更改为:
var dept_ids = string.Join(" ", depts.ToStringArray());
from f in CUSTOMERS
where dept_ids.IndexOf(Convert.ToString(f.DEPT_id)) != -1
select f.NAME
使用IndexOf()
修复了错误,但使查询变慢。有没有其他方法可以解决这个问题?非常感谢。
【问题讨论】:
like so 怎么样(将其分成可管理的部分)。其他(非 LINQ)选项涉及 CSV 和“拆分”UDF,以及表值参数(在 SQL2008 中)。 马克,如果我有从 1 到 2000 的各种参数,你能解释一下contain
的最佳替代品吗?我知道这会在数据库中创建一堆计划,但似乎like <input parameter> '%<search field>%'
的使用将花费更多的数据库资源时间。我应该使用什么?
Entity Framework不存在2100参数限制问题:***.com/questions/8898564/…
您尝试过任何解决方案吗?未标记为无
当搜索DEPT_id
等于1时,会发现任何id的任何数字都有1!我错过了什么吗?
【参考方案1】:
我的解决方案(Guids
是您要过滤的 id 列表):
List<MyTestEntity> result = new List<MyTestEntity>();
for(int i = 0; i < Math.Ceiling((double)Guids.Count / 2000); i++)
var nextGuids = Guids.Skip(i * 2000).Take(2000);
result.AddRange(db.Tests.Where(x => nextGuids.Contains(x.Id)));
this.DataContext = result;
【讨论】:
与其使用 Ceiling(并在 Skip 中相乘)并递增 1,不如使用 Count 作为条件并递增 2000。同时将其设为常量以使其可配置。【参考方案2】:为什么不在 sql 中编写查询并附加您的实体?
我在 Linq 工作已经有一段时间了,但这里是:
IQuery q = Session.CreateQuery(@"
select *
from customerTable f
where f.DEPT_id in (" + string.Join(",", depts.ToStringArray()) + ")");
q.AttachEntity(CUSTOMER);
当然,您需要防止注射,但这不应该太难。
【讨论】:
谢谢乔尔。让我试试,我会告诉你进展如何。 警告:整数可以,但字符串:注意 SQL 注入。 大概你想在某个地方加一个逗号吧,乔尔? 是的,在编写动态 sql 时注入总是一个问题,但使用整数会更安全。加了逗号。 ;) 嗨乔尔,再次感谢您抽出时间回答我的问题。 :-)【参考方案3】:您将需要查看LINQKit project,因为其中某处有一种将此类语句批处理以解决此问题的技术。我相信这个想法是使用 PredicateBuilder 将本地集合分解成更小的块,但我没有详细查看解决方案,因为我一直在寻找一种更自然的方法来处理这个问题。
不幸的是,从Microsoft's response to my suggestion 看来,为了解决此问题,没有计划为 .NET Framework 4.0 甚至后续服务包解决此问题。
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=475984
更新:
我已经在 MSDN 论坛上针对 LINQ to SQL 或 ADO.NET Entity Framework 进行了一些讨论。请参阅这些帖子以获取有关这些主题的更多信息,并查看我使用 XML 和 SQL UDF 提出的临时解决方法。
【讨论】:
【参考方案4】:我有类似的问题,我有两种方法可以解决它。
-
Intersect方法
加入 ID
为了获取不在列表中的值,我使用了Except 方法或左连接。
更新
EntityFramework 6.2 成功运行以下查询:
var employeeIDs = Enumerable.Range(3, 5000);
var orders =
from order in Orders
where employeeIDs.Contains((int)order.EmployeeID)
select order;
【讨论】:
你能举个例子吗?【参考方案5】:在将部门列表作为参数传递给 Linq 生成的 IN 语句之前,您始终可以将它们划分为更小的集合。见这里:
Divide a large IEnumerable into smaller IEnumerable of a fix amount of item
【讨论】:
以上是关于使用 Contains() 时达到 2100 参数限制 (SQL Server)的主要内容,如果未能解决你的问题,请参考以下文章
LINQ to SQL查询中的C#Dynamic WHERE子句