【发布时间】:2021-01-30 16:56:42
【问题描述】:
我有一个具有以下架构的数据库:
现在,我正在尝试提取域的所有登录页面,并按与某个组匹配的第一个 UrlFilter 的 FilterType 对它们进行排序。这是我迄今为止提出的 LINQ:
var baseQuery = DbSet.AsNoTracking()
.Where(e => EF.Functions.Contains(EF.Property<string>(e, "Url"), $"\"{searchTerm}*\""))
.Where(e => e.DomainLandingPages.Select(lp => lp.DomainId).Contains(domainId));
var count = baseQuery.Count();
var page = baseQuery
.Select(e => new
{
LandingPage = e,
UrlFilter = e.LandingPageUrlFilters.FirstOrDefault(f => f.UrlFilter.GroupId == groupId)
})
.Select(e => new
{
e.LandingPage,
FilterType = e.UrlFilter == null ? UrlFilterType.NotCovered : e.UrlFilter.UrlFilter.UrlFilterType
})
.OrderBy(e => e.FilterType)
.Skip(10).Take(75).ToList();
现在,虽然这在技术上可行,但执行时间从 10 到 30 秒不等,速度很慢,这对于用例来说还不够好。 LINQ 被转换为以下 SQL:
SELECT [l1].[Id], [l1].[LastUpdated], [l1].[Url], CASE
WHEN (
SELECT TOP(1) [l].[LandingPageId]
FROM [LandingPageUrlFilters] AS [l]
INNER JOIN [UrlFilters] AS [u] ON [l].[UrlFilterId] = [u].[Id]
WHERE ([l1].[Id] = [l].[LandingPageId]) AND ([u].[GroupId] = @__groupId_3)) IS NULL THEN 4
ELSE (
SELECT TOP(1) [u0].[UrlFilterType]
FROM [LandingPageUrlFilters] AS [l0]
INNER JOIN [UrlFilters] AS [u0] ON [l0].[UrlFilterId] = [u0].[Id]
WHERE ([l1].[Id] = [l0].[LandingPageId]) AND ([u0].[GroupId] = @__groupId_3))
END AS [FilterType]
FROM [LandingPages] AS [l1]
WHERE CONTAINS([l1].[Url], @__Format_1) AND @__domainId_2 IN (
SELECT [d].[DomainId]
FROM [DomainLandingPages] AS [d]
WHERE [l1].[Id] = [d].[LandingPageId]
)
ORDER BY CASE
WHEN (
SELECT TOP(1) [l2].[LandingPageId]
FROM [LandingPageUrlFilters] AS [l2]
INNER JOIN [UrlFilters] AS [u1] ON [l2].[UrlFilterId] = [u1].[Id]
WHERE ([l1].[Id] = [l2].[LandingPageId]) AND ([u1].[GroupId] = @__groupId_3)) IS NULL THEN 4
ELSE (
SELECT TOP(1) [u2].[UrlFilterType]
FROM [LandingPageUrlFilters] AS [l3]
INNER JOIN [UrlFilters] AS [u2] ON [l3].[UrlFilterId] = [u2].[Id]
WHERE ([l1].[Id] = [l3].[LandingPageId]) AND ([u2].[GroupId] = @__groupId_3))
END
OFFSET @__p_4 ROWS FETCH NEXT @__p_5 ROWS ONLY
现在我的问题是,我怎样才能提高它的执行时间?通过 SQL 或 LINQ
编辑:所以我一直在修改一些原始 SQL,这就是我想出的:
with matched_urls as (
select l.id, min(f.urlfiltertype) as Filter
from landingpages l
join landingpageurlfilters lpf on lpf.landingpageid = l.id
join urlfilters f on lpf.urlfilterid = f.id
where f.groupid = @groupId
and contains(Url, '"barz*"')
group by l.id
) select l.id, 5 as Filter
from landingpages l
where @domainId in (
select domainid
from domainlandingpages dlp
where l.id = dlp.landingpageid
) and l.id not in (select id from matched_urls ) and contains(Url, '"barz*"')
union select * from matched_urls
order by Filter
offset 10 rows fetch next 30 rows only
这执行得还不错,将执行时间缩短到约 5 秒。由于这将用于表搜索,但我想进一步降低它。有什么方法可以改进这个 SQL 吗?
【问题讨论】:
-
为此使用原始 SQL。容易得多。并非所有事情都必须通过 LINQ。
-
@jeroenh 您能否大致介绍一下查询的外观?我对 SQL 不太熟悉,尤其是优化。
-
你的
basequery够好吗?尝试只运行它。实际上,我更愿意从Join表开始查询 -DbSet<DomainLandingPages>.AsNoTracking().Where(x => x.domainId == domainId)... - 它生成Inner Join语句而不是In
标签: c# sql-server entity-framework linq tsql