我需要通过数据库中的产品搜索产品,并且我希望以正确的方式进行设置,以便在存在大量行(1,000,000)时可以获得稳定的性能。我对LINQ和EF有一定的经验,但从来没有编写任何搜索算法,我有以下代码,但只是有一些挥之不去的问题。
context.products.Where(i => i.Name.ToLower().Contains(searchText.ToLower());
我还需要搜索说明。
context.products.Where(i => i.Description.ToLower().Contains(searchText.ToLower());
此上下文中的.ToLower()
会降低性能吗?
我在Name
和FullText
上有一个常规索引吗?这是否合适,并且常规索引适用于.contains()
?
我应该使用LINQ还是其他方法?
有没有办法可以在名称/描述中获取搜索文本的次数?
谢谢
答案 0 :(得分:1)
请不要使用较低的,因为它会显着影响性能 使用以下之一:
StringComparison.OrdinalIgnoreCase
StringComparison.CurrentCultureIgnoreCase
由于您正在使用contains,它将被翻译为'%text%',因此sql server不太可能使用索引。如果您实现FullText搜索,则必须使用存储过程来使用全文搜索的优势。
通常,如果您使用的是最新的实体框架,那么您应该获得相当不错的性能,因为它们在版本5中有了一些显着的性能改进。
答案 1 :(得分:1)
我会认真考虑编写一个存储过程来执行此操作,或者使用SqlQuery
在DbContext中编写原始sql。如果我正在写这段代码,那就是我要做的。对我来说,EntityFramework和performant从未真正走到一起。
答案 2 :(得分:1)
在我的情况下,我不想使用存储过程。我正在使用Entity Framework,这就是我想要使用的东西!
查看此方法是否可以为您提供帮助。
public static IQueryable<T> LikeOr<T>(this IQueryable<T> source, string columnName, string searchTerm)
{
IEnumerable<string> words =
searchTerm.Split(new[] {" "}, StringSplitOptions.RemoveEmptyEntries).Where(x => x.Length > 1);
var sb = new StringBuilder();
for (int i = 0; i < words.Count(); i++)
{
if (i != 0)
sb.Append(" || ");
sb.Append(string.Format("{0}.Contains(@{1})", columnName, i));
}
return source.Where(sb.ToString(), words.ToArray());
}
以上所有方法都会构建一个SQL字符串,然后将其传递给Dynamic LINQ Where方法。在高级别上,所有这一切都允许您仅在需要的地方使用直接sql,而不是在SQL中编写整个查询。 这是通过以下方式调用的:
public List<Book> SearchForBooks(string phrase)
{
return _db.Books.Include(x=> x.Images).LikeOr("Title", phrase).OrderBy(x => x.Title)
.Take(6).Select(x => x).ToList()
.OrderByCountDescending("Title", phrase);
}
这是由Microsoft创建的动态LINQ dll实现的,但不包含在框架中。 Dynamic LINQ这将使您在某些方面更加灵活。