我的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更快?
答案 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);
}