使用 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子句

MySQL:选择问题

服务器上的 Where In 子句错误仅支持最多 2100 个参数

仅当元素具有特定子元素时才向元素添加规则

Deno 已经完成 2100 万美元 A 轮融资

实体框架核心 - .Contains() - 为啥转义而不是参数化?