简体   繁体   English

改善自动完成LINQ查询的性能

[英]Improve the performance of an AutoComplete LINQ Query

I have some massive searches happening for my AutoComplete and was wondering if someone could give any ideas to improve the performance. 我的AutoComplete正在进行大量搜索,想知道是否有人可以提出任何建议来提高性能。

What happens: 怎么了:

1) At application launch I am saving all database entries on the memory. 1)在应用程序启动时,我将所有数据库条目保存在内存中。

2) User types in the search box to initiate AutoComplete: 2)用户在搜索框中键入以启动自动完成:

$("#MatterCode").width(110).kendoAutoComplete({
        minLength: 3,
        delay: 10,
        dataTextField: "MatterCode",
        template: '<div class="autoCompleteResultsCode"> ${ data.ClientCode } - ${ data.MatterCode } - ${ data.ClientName } - ${ data.MatterName }</div>',
        dataSource: {
            serverFiltering: true,
            transport: {
                read: "/api/matter/AutoCompleteByCode",
                parameterMap: function() {
                    var matterCode = $("#MatterCode").val();
                    return { searchText: matterCode };
                }
            }
        }, //More Stuff here

3) It goes to my controller class: 3)进入我的控制器类:

public JsonResult AutoCompleteByCode(string searchText)
{
    if (string.IsNullOrEmpty(searchText))
    {
        Response.StatusCode = 500;
        return Json(new
        {
            Error = "search string can't be empty"
        });
    }

    var results = _publishedData.GetMattersForAutoCompleteByCode(searchText).Select(
            matter => new
            {
                MatterCode = matter.Code,
                MatterName = matter.Name,
                ClientCode = matter.Client.Code,
                ClientName = matter.Client.Name
            });
    return Json(results);
}

4) Which goes into the DAL (objects starting with '_' are Memory Objects) 4)进入DAL的对象(以“ _”开头的对象是内存对象)

public virtual IEnumerable<Matter> GetMattersForAutoCompleteByCode(string input)
{
    InvalidateCache();
    IEnumerable<Matter> results;
    //Searching Matter Object on all 4 given parameters by input.

    if (_lastMatters != null && input.StartsWith(_lastSearch) && _lastMatters.Any())
    {
        results = _lastMatters.Where(m => m.IsInputLike(input)).OrderBy(m => m.Code);
        _lastMatters = results;
    }
    else
    {
        results = _matters.Where(m => m.IsInputLike(input)).OrderBy(m => m.Code);
        _lastMatters = results;
    }

    _lastSearch = input;

    return results.Take(10).ToList();
}

5) isInputLike is an internal bool method 5)isInputLike是一个内部布尔方法

internal bool IsInputLike(string input)
{
    //Check to see if the input statement exists in any of the 4 fields
    bool check = (Code.ToLower().Contains(input.Trim().ToLower()) 
            || Name.ToLower().Contains(input.Trim().ToLower()) 
            || ClientCode.ToLower().Contains(input.Trim().ToLower()) 
            || ClientName.ToLower().Contains(input.Trim().ToLower()));

    return check;
}

Now the result set that I have to work with can range over 100,000. 现在,我必须使用的结果集可能超过100,000。 Now the first Autocomplete of any new query has to search through 400,000 records and I can't think of a way to improve the performance without sacrificing the feature. 现在,任何新查询的第一个自动完成功能都必须搜索40万条记录,我想不出一种不牺牲功能就可以提高性能的方法。

Any ideas? 有任何想法吗? Is SQL stored proc calls faster than LINQ? SQL存储的proc调用是否比LINQ更快?

I'm not much of an asp/http guy but when I see this: 我不是一个asp / http家伙,但是当我看到此信息时:

internal bool IsInputLike(string input)
{
    //Check to see if the input statement exists in any of the 4 fields
    bool check = (Code.ToLower().Contains(input.Trim().ToLower()) 
        || Name.ToLower().Contains(input.Trim().ToLower()) 
        || ClientCode.ToLower().Contains(input.Trim().ToLower()) 
        || ClientName.ToLower().Contains(input.Trim().ToLower()));

    return check;
}

I think you are creating a lot of new string; 我认为您正在创建很多新的字符串。 and that has to take some time. 这需要一些时间。 Try this and see if this improves your performance 试试看,看看这是否可以改善您的表现

var inp = input.Trim();
bool chk = (Code.IndexOf(inp, StringComparison.CurrentCultureIgnoreCase) > -1)
                || (Name.IndexOf(inp, StringComparison.CurrentCultureIgnoreCase) > -1)
                || (ClientCode.IndexOf(inp, StringComparison.CurrentCultureIgnoreCase) > -1)
                || (ClientName.IndexOf(inp, StringComparison.CurrentCultureIgnoreCase) > -1);

This first line (that creates inp) isn't that important since the compiler should optimize repeated usage, but I think it reads better. 第一行(创建inp)并不重要,因为编译器应该优化重复使用,但是我认为它读起来更好。

The IndexOf method will not create new strings and with the StringComparison parameter you can avoid creating all the ToLower strings. IndexOf方法不会创建新的字符串,并且使用StringComparison参数可以避免创建所有ToLower字符串。

I think the main issue here is you placing the 400k objects in memory to start with. 我认为这里的主要问题是首先将400k对象放置在内存中。 SQL is not all that slow, it's better to start with a limited set of data in the first place. SQL并没有那么慢,最好首先从一组有限的数据开始。

one obvious optimisation is: 一个明显的优化是:

internal bool IsInputLike(string input)
{
    string input = input.Trim().ToLower();
    //Check to see if the input statement exists in any of the 4 fields
    bool check = (Code.ToLower().Contains(input) 
            || Name.ToLower().Contains(input) 
            || ClientCode.ToLower().Contains(input) 
            || ClientName.ToLower().Contains(input));

    return check;
}

but personally, I would keep the data where it belongs, in the SQL server (if that's what you are using). 但就我个人而言,我会将数据保留在SQL Server中(如果您使用的是它)。 Some indexing and the proper queries could make this faster. 一些索引和适当的查询可以使此过程更快。

When I see this code I start wondering: 当我看到这段代码时,我开始怀疑:

public virtual IEnumerable<Matter> GetMattersForAutoCompleteByCode(string input)
{
    InvalidateCache();
    IEnumerable<Matter> results;
    //Searching Matter Object on all 4 given parameters by input.

    if (_lastMatters != null && input.StartsWith(_lastSearch) && _lastMatters.Any())
    {
        results = _lastMatters.Where(m => m.IsInputLike(input)).OrderBy(m => m.Code);
        _lastMatters = results;
    }
    else
    {
        results = _matters.Where(m => m.IsInputLike(input)).OrderBy(m => m.Code);
        _lastMatters = results;
    }

    _lastSearch = input;

    return results.Take(10).ToList();
}

why do you need to order? 为什么需要订购? Why does a dropdown autocomplete need to filter on 4 items? 为什么下拉式自动填充功能需要过滤4个项目? if you only take 10 anyway can't you just not order? 如果你只拿10点,就不能不点菜吗? See if removing the orderby gives you any better results, especially in the else statement where you'll have many results. 查看删除orderby是否会给您带来更好的结果,尤其是在else语句中,您将获得很多结果。

personally i'd go all in for LINQ to SQL and let the SQL server do the searching. 我个人将全力以赴使用LINQ to SQL,并让SQL Server进行搜索。 optimize the indexing on this table and it'll be much faster. 优化此表上的索引编制,它将更快。

Well i recommend you to create a view that contains all of the names eg (code, name, Clientcode, ClientName) into a single column concatenated say FullName and replace your IsInputLike(..) as below: 好吧,我建议您创建一个包含所有名称的视图,例如将所有名称(如(代码,名称,Clientcode,ClientName)放入一个连接成FullName的单列中,并替换IsInputLike(..)如下:

internal bool IsInputLike(string input)
{
    //Check to see if the input statement exists in any of the 4 fields
    return FullName.Contains(input);

}

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

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