【问题标题】:LINQ2SQL select rows based on large whereLINQ2SQL 根据大 where 选择行
【发布时间】:2011-05-30 19:22:40
【问题描述】:

我正在使用 LINQ2SQL 在 SQL(精简版)数据库中搜索一堆 int32。

我的主要问题是我有一个很大的 int32 列表(数千个),我想要 DB 中的所有记录,其中 DB 中的 id 字段与我的任何 int32 匹配。目前我一次选择一行,有效地搜索索引数千次。

我该如何优化呢?临时表?

【问题讨论】:

  • 向我们展示您当前使用的 LINQ 查询。
  • 你从哪里得到这个 int32 列表?
  • 我从一个复杂的绝密事物中得到了 int32 的列表。有关系吗? ;) 这是寻找图片中某些关键点的算法的输出。

标签: c# sql linq-to-sql query-optimization


【解决方案1】:

听起来您可以使用 Contains 查询:

int[] intArray = ...;
var matches = from item in context.SomeTable 
              where intArray.Contains(item.id) 
              select item;

【讨论】:

  • 这不适用于超过 2000 个值 - 您会在 SQl 日志中遇到严重错误。
  • 手头没有 SQL,但与执行带有超过一定数量参数的查询有关。
  • 借助 Google 的力量:bit.ly/mgahHX,以及围绕此问题的 SO 问题:bit.ly/j68myx
  • 有趣,我不知道这个限制
  • @ck 如果构建 OR 表达式的动态 where 语句,会出现同样的限制吗?
【解决方案2】:

要搜索数千个值,您的选择是:

  • 将 XML 块发送到存储过程(复杂但可行)
  • 创建临时表,批量上传数据,然后加入其中(可能会导致并发问题)
  • 执行多个查询(即将您的一组 ID 分成大约一千个的块并使用 BrokenGlass 的解决方案)

我不确定您可以使用精简版做什么。

【讨论】:

    【解决方案3】:

    在 SQL 表中插入整数然后执行:

    var items = from row in table
                join intRow in intTable on row.TheIntColumn equals intRow.IntColumn
                select row;
    

    编辑 1 和 2: 更改了答案,因此他加入了 2 个表,没有集合。

    【讨论】:

    • 你不能加入 Linq2Sql 中的列表
    • 好吧,那么我会再次编辑我的答案,说如果他想使用这个解决方案,他必须做我在编辑中写的事情;-)
    • 尝试了此页面上的其他提示。这是迄今为止最快的。
    • 您应该查看“LinqPad”。我最喜欢该程序的一项功能是您可以看到生成的 SQL 查询。这样,您可以稍微调整您的代码,让“Over-the-top”优化的 SQL 服务器处理负载。
    【解决方案4】:

    我的偏好是为搜索编写一个存储过程。如果您正在搜索的字段上有一个索引,那么当要处理的行数增加时,这将使您的生活变得更加轻松。

    您将遇到的复杂性是编写一个可以从输入参数执行 IN 子句的选择语句。您需要有一个表值函数将字符串(Id 的)转换为列并在 IN 子句中使用该列。 喜欢:

    Select *
    From SomeTable So
    Where So.ID In (Select Column1 From dbo.StringToTable(InputIds))
    

    【讨论】:

      【解决方案5】:

      在厌倦了编写手动批处理代码之后,我想出了这个 linq 解决方案。 它并不完美(即批次并不完全完美),但它解决了问题。 当您不允许编写存储过程或 sql 函数时非常有用。适用于几乎所有 linq 表达式。

      享受:

          public static IQueryable<TResultElement> RunQueryWithBatching<TBatchElement, TResultElement>(this IList<TBatchElement> listToBatch, int batchSize, Func<List<TBatchElement>, IQueryable<TResultElement>> initialQuery)
          {
              return RunQueryWithBatching(listToBatch, initialQuery, batchSize);
          }
      
          public static IQueryable<TResultElement> RunQueryWithBatching<TBatchElement, TResultElement>(this IList<TBatchElement> listToBatch, Func<List<TBatchElement>, IQueryable<TResultElement>> initialQuery)
          {
              return RunQueryWithBatching(listToBatch, initialQuery, 0);
          }
      
          public static IQueryable<TResultElement> RunQueryWithBatching<TBatchElement, TResultElement>(this IList<TBatchElement> listToBatch, Func<List<TBatchElement>, IQueryable<TResultElement>> initialQuery, int batchSize)
          {
              if (listToBatch == null)
                  throw new ArgumentNullException("listToBatch");
      
              if (initialQuery == null)
                  throw new ArgumentNullException("initialQuery");
      
              if (batchSize <= 0)
                  batchSize = 1000;
      
              int batchCount = (listToBatch.Count / batchSize) + 1;
      
              var batchGroup = listToBatch.AsQueryable().Select((elem, index) => new { GroupKey = index % batchCount, BatchElement = elem }); // Enumerable.Range(0, listToBatch.Count).Zip(listToBatch, (first, second) => new { GroupKey = first, BatchElement = second });
      
              var keysBatchGroup = from obj in batchGroup
                                           group obj by obj.GroupKey into grouped
                                           select grouped;
      
              var groupedBatches = keysBatchGroup.Select(key => key.Select((group) => group.BatchElement));
      
              var map = from employeekeysBatchGroup in groupedBatches
                        let batchResult = initialQuery(employeekeysBatchGroup.ToList()).ToList() // force to memory because of stupid translation error in linq2sql
                        from br in batchResult
                        select br;
      
              return map;
          }
      

      用法:

      using (var context = new SourceDataContext())
      {
          // some code
          var myBatchResult = intArray.RunQueryWithBatching(batch => from v1 in context.Table where batch.Contains(v1.IntProperty) select v1, 2000);
          // some other code that makes use of myBatchResult
      }
      

      然后要么使用结果,要么展开到列表,或者你需要的任何东西。只要确保您不会丢失 DataContext 引用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-01-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多