【问题标题】:Hitting the 2100 parameter limit (SQL Server) when using Contains()使用 Contains() 时达到 2100 参数限制 (SQL Server)
【发布时间】: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参数限制问题:stackoverflow.com/questions/8898564/…
  • 您尝试过任何解决方案吗?未标记为无
  • 当搜索DEPT_id等于1时,会发现任何id的任何数字都有1!我错过了什么吗?

标签: sql-server linq parameters limit


【解决方案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 SQLADO.NET Entity Framework 进行了一些讨论。请参阅这些帖子以获取有关这些主题的更多信息,并查看我使用 XML 和 SQL UDF 提出的临时解决方法。

【讨论】:

    【解决方案4】:

    我有类似的问题,我有两种方法可以解决它。

    1. Intersect方法
    2. 加入 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

    【讨论】:

      猜你喜欢
      • 2019-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-13
      • 1970-01-01
      相关资源
      最近更新 更多