提高AutoComplete LINQ查询的性能

时间:2013-10-09 00:12:04

标签: c# ajax linq

我的AutoComplete发生了大量搜索,并且想知道是否有人可以提出改进性能的想法。

会发生什么:

1)在应用程序启动时,我将保存内存中的所有数据库条目。

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)它转到我的控制器类:

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)进入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是一个内部bool方法

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;
}

现在我必须使用的结果集可以超过100,000。现在,任何新查询的第一个自动完成都必须搜索400,000条记录,我无法想到在不牺牲功能的情况下提高性能的方法。

有什么想法吗? SQL存储过程调用是否比LINQ更快?

3 个答案:

答案 0 :(得分:2)

我不是一个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;
}

我认为你正在创造很多新的字符串;这需要一些时间。试试这个,看看这是否会提高你的表现

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);

第一行(创建inp)并不重要,因为编译器应优化重复使用,但我认为它读得更好。

IndexOf方法不会创建新字符串,使用StringComparison参数可以避免创建所有ToLower字符串。

答案 1 :(得分:2)

我认为这里的主要问题是你将400k对象放在内存中开始。 SQL并不是那么慢,最好先从一组有限的数据开始。

一个明显的优化是:

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;
}

但就个人而言,我会将数据保存在SQL服务器中(如果这就是您所使用的)。 一些索引和正确的查询可以使这更快。

当我看到这段代码时,我开始怀疑:

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();
}

为什么需要订购?为什么下拉菜单自动完成需要过滤4个项目?如果你只拿10个,不管你不能订购?看看删除orderby是否会给你带来更好的结果,特别是在你会得到很多结果的else语句中。

我个人会全力以赴地使用LINQ to SQL并让SQL服务器进行搜索。优化此表上的索引,它会更快。

答案 2 :(得分:1)

我建议你创建一个包含所有名称的视图,例如(代码,名称,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);

}