LINQ2SQL基于大型where选择行

本文关键字:选择 where 于大型 LINQ2SQL | 更新日期: 2023-09-27 17:57:55

我正在使用LINQ2SQL在SQL(Compact edition)数据库中搜索一堆int32。

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

如何对此进行优化?温度表

LINQ2SQL基于大型where选择行

这听起来像是可以使用Contains查询:

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

对于成千上万个值的搜索,您的选项是:

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

我不确定你能用Compact Edition做什么。

在SQL表中插入int,然后执行:

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

编辑1&2:更改了答案,所以他加入了2个表,没有集合。

我的首选是为搜索编写一个存储过程。如果你在搜索的字段上有一个索引,那么当将来要处理的行数增加时,你的生活会轻松很多。

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

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

在厌倦了编写手动批处理代码之后,我提出了这个linq解决方案。它并不完美(即批次并不完全完美),但它解决了问题。在不允许编写存储的proc或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
}

然后使用result,或者展开到列表,或者您需要的任何内容。只需确保您不会丢失DataContext引用。