【发布时间】:2019-12-12 12:05:56
【问题描述】:
我有一个 .net 核心 API,我正在尝试使用 .Contains() 搜索 440 万条记录。这显然非常慢 - 26 秒。我只是查询一列,它是记录的名称。在处理数百万条记录时,这个问题一般如何解决?
我之前从未处理过数百万条记录,因此除了明显更改 .Select 和 .Take 之外,我还没有尝试过任何过于激烈的操作。不过,我已经为此花费了很多时间。
.Where 中包含的其他过滤器仅在用户选择在前端使用它们时使用 - 真正的问题只是按 CompanyName 搜索。
注意;我在返回结果时使用 .ToArray()。
我在数据库中有索引,但无法为 CompanyName 添加索引,因为它是 Nvarchar(MAX)。
我也查看了执行计划,它并没有真正显示出任何异常。
query = _context.Companies.Where(
c => c.CompanyName.Contains(paging.SearchCriteria.companyNameFilter.ToUpper())
&& c.CompanyNumber.StartsWith(
string.IsNullOrEmpty(paging.SearchCriteria.companyNumberFilter)
? paging.SearchCriteria.companyNumberFilter.ToUpper()
: ""
)
&& c.IncorporationDate > paging.SearchCriteria.companyIncorperatedGreaterFilter
&& c.IncorporationDate < paging.SearchCriteria.companyIncorperatedLessThanFilter
)
.Select(x => new Company() {
CompanyName = x.CompanyName,
IncorporationDate = x.IncorporationDate,
CompanyNumber = x.CompanyNumber
}
)
.Take(10);
我预计查询大约需要 1 / 2 秒,因为当我在 ssms 中执行类似查询时大约需要 1 / 2 秒。
这是提交给数据库的代码:
Microsoft.EntityFrameworkCore.Database.Command: Information: Executing DbCommand [Parameters=[@__p_4='?' (DbType = Int32), @__ToUpper_0='?' (Size = 4000), @__p_1='?' (Size = 4000), @__paging_SearchCriteria_companyIncorperatedGreaterFilter_2='?' (DbType = DateTime2), @__paging_SearchCriteria_companyIncorperatedLessThanFilter_3='?' (DbType = DateTime2), @__p_5='?' (DbType = Int32)], CommandType='Text', CommandTimeout='30']
SELECT [t].[CompanyName], [t].[IncorporationDate], [t].[CompanyNumber]
FROM (
SELECT TOP(@__p_4) [c].[CompanyName], [c].[IncorporationDate], [c].[CompanyNumber], [c].[ID]
FROM [Companies] AS [c]
WHERE (((((@__ToUpper_0 = N'') AND @__ToUpper_0 IS NOT NULL) OR (CHARINDEX(@__ToUpper_0, [c].[CompanyName]) > 0)) AND (((@__p_1 = N'') AND @__p_1 IS NOT NULL) OR ([c].[CompanyNumber] IS NOT NULL AND (@__p_1 IS NOT NULL AND (([c].[CompanyNumber] LIKE [c].[CompanyNumber] + N'%') AND (((LEFT([c].[CompanyNumber], LEN(@__p_1)) = @__p_1) AND (LEFT([c].[CompanyNumber], LEN(@__p_1)) IS NOT NULL AND @__p_1 IS NOT NULL)) OR (LEFT([c].[CompanyNumber], LEN(@__p_1)) IS NULL AND @__p_1 IS NULL))))))) AND ([c].[IncorporationDate] > @__paging_SearchCriteria_companyIncorperatedGreaterFilter_2)) AND ([c].[IncorporationDate] < @__paging_SearchCriteria_companyIncorperatedLessThanFilter_3)
) AS [t]
ORDER BY [t].[IncorporationDate] DESC
OFFSET @__p_5 ROWS FETCH NEXT @__p_4 ROWS ONLY
已解决!在这两个答案的帮助下!
最后,按照建议,我尝试了全文搜索,这种搜索速度很快,但搜索结果的准确性有所降低。为了更准确地过滤这些结果,我在应用全文搜索后在查询中使用了 .Contains。
这是有效的代码。希望这对其他人有所帮助。
//查询 = _context.Companies //.Where(c => c.CompanyName.StartsWith(paging.SearchCriteria.companyNameFilter.ToUpper()) //&& c.CompanyNumber.StartsWith(string.IsNullOrEmpty(paging.SearchCriteria.companyNumberFilter) ? paging.SearchCriteria.companyNumberFilter.ToUpper() : "") //&& c.IncorporationDate > paging.SearchCriteria.companyIncorperatedGreaterFilter && c.IncorporationDate new Company() { CompanyName = x.CompanyName, IncorporationDate = x.IncorporationDate, CompanyNumber = x.CompanyNumber }).Take(10);
query = _context.Companies.Where(c => EF.Functions.FreeText(c.CompanyName, paging.SearchCriteria.companyNameFilter.ToUpper()));
query = query.Where(x => x.CompanyName.Contains(paging.SearchCriteria.companyNameFilter.ToUpper()));
(为简单起见,我暂时排除了其他过滤器)
【问题讨论】:
-
您能否更新您的问题并显示您在 SSMS 中使用的 SQL 查询?
-
请与我们分享确切 SQL 正在提交到服务器 - stackoverflow.com/a/44180537/34092。