简体   繁体   English

如何“拆分”或优化Linq to Sql查询。

[英]How to “split up” or optimize a Linq to Sql query.

Background 背景

We have a AdvancedSearchModel which is just a struct with several strings. 我们有一个AdvancedSearchModel ,它只是一个带有多个字符串的结构。 SerialNumbers is a string of serial numbers (10 characters in length) separated by commas. SerialNumbers是一串用逗号分隔的序列号(长度为10个字符)。 This is split into an array of strings. 这被拆分为字符串数组。 We are searching over a table Devices which has a column, SerialNumber . 我们正在搜索具有一列SerialNumber Devices表。 We need to partial match these search phrases as well, which explains the Any and Contains usage. 我们还需要对这些搜索短语进行部分匹配,以解释“ Any和“ Contains用法。 There are about 10 strings in the AdvancedSearchModel and we are able to apply each to the query without issue. AdvancedSearchModel中大约有10个字符串,我们可以将每个字符串毫无问题地应用于查询。

public static IQueryable<Device> ApplySearchQuery(IQueryable<Device> query, AdvancedSearchModel searchModel)
{
    if (!String.IsNullOrWhiteSpace(searchModel.SerialNumbers))
    {
        string[] serialNumbers = searchModel.SerialNumbers.Split(',');
        query = query.Where(d => serialNumbers.Any(s => d.SerialNumber.Contains(s))); 

     }
     // ... more queries added that are part of the search model
}

The Issue 问题

Let me preface this with when this was implemented, we expected about 10 serial numbers to be search at once max. 让我以实施此操作为开头,我们希望一次最多搜索约10个序列号。 However , We've found users putting up to 100 Serial numbers. 但是 ,我们发现用户最多输入100个序列号。 We get an error that the query is too deeply nested from this. 我们收到一个错误,即查询从此嵌套得太深了。 So even if we only search by SerialNumbers, it will throw an exception when serialNumbers grows above 43 elements. 因此,即使我们仅按序列号进行搜索,当serialNumbers超过43个元素时,它也会引发异常。

I'm not really sure how to split up this query, as individually they are simple (albeit we expect the result to be slow). 我不太确定如何拆分此查询,因为它们分别很简单(尽管我们期望结果很慢)。

Perhaps we could have an ArrayList of string[] of size ~25, and grow this array list, ie if a user searches for 100 serial numbers, then the ArrayList would have 4 string arrays, but I'm not sure that really helps... 也许我们可以有一个大约为25的string[]ArrayList ,并扩展此数组列表,即,如果用户搜索100个序列号,则ArrayList将具有4个字符串数组,但是我不确定这是否真的有用。 ..

Any ideas? 有任何想法吗?

I imagine you can get EF to generate a flat OR statement instead of a nested subquery if you generate the OR expression manually: 我想如果您手动生成OR表达式,则可以让EF生成平面OR语句而不是嵌套的子查询:

string[] serialNumbers = searchModel.SerialNumbers.Split(',');
// GetMethod defined at http://www.codeducky.org/10-utilities-c-developers-should-know-part-two/
var stringContainsMethod = Helpers.GetMethod((string s) => s.Contains(default(string)));
var serialNumberProperty = Helpers.GetProperty((Device d) => d.SerialNumber);
var parameter = Expression.Parameter(typeof(Device));

// generate a condition d.SerialNumber.Contains(sn) for each sn
var conditions = serialNumbers.Select(sn => Expression.Call(  
    Expression.MakeMemberAccess(parameter, serialNumberProperty), // d.SerialNumber
    stringContainsMethod, // the method to invoke
    Expression.Constant(sn) // equivalent of a string literal for the serial number
));

// generate a lambda we can pass to Where: 
// d => d.SerialNumber.Contains(sn1) || d.SerialNumber.Contains(sn1) || ..
var predicate = Expression.Lambda<Func<Device, bool>>(
    // merge each condition with ORs
    conditions.Aggregate<Expression>((c1, c2) => Expression.OrElse(c1, c2)),
    parameter
);

// apply the predicate
query = query.Where(predicate);

Batching will also, work of course. 批处理当然也可以。 However, it shouldn't be necessary for so small an argument set. 但是,对于这么小的参数集,则没有必要。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM