1

我对我的 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 快?

4

3 回答 3

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 字符串。

于 2013-10-09T02:27:00.417 回答
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 服务器进行搜索。优化这张表的索引,它会快得多。

于 2013-10-09T03:02:32.640 回答
1

好吧,我建议您创建一个包含所有名称的视图,例如(代码、名称、客户端代码、客户端名称)到一个串联的单个列中,例如 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);

}
于 2013-10-09T05:48:21.460 回答