【发布时间】:2021-12-14 05:07:52
【问题描述】:
我有Website(Id) 表,每条记录可能有多个关联的CheckLog(FK WebsiteId) 条目。 CheckLog 也有一个复合索引 [WebsiteId, CreatedTime]。 Website 只有大约 20 条记录,但加班时间 CheckLog 会增长,当时有 300 万条记录我有这个问题。 (请参阅问题末尾使用 EF Core 的架构)。
我的一个常见查询是查询所有Websites 的列表,以及零/一个 最新的CheckLog 记录:
return await this.ctx.Websites.AsNoTracking()
.Select(q => new WebsiteListItem()
{
Website = q,
LatestCheckLog = q.CheckLogs
.OrderByDescending(q => q.CreatedTime)
.FirstOrDefault(),
})
.ToListAsync();
我相信[WebsiteId, CreatedTime] 索引应该会有所帮助。但是,查询需要大约 11 秒才能执行。这是翻译后的查询以及EXPLAIN QUERY PLAN:
SELECT "w"."Id", "t0"."Id", "t0"."CreatedTime", "t0"."WebsiteId"
FROM "Websites" AS "w"
LEFT JOIN (
SELECT "t"."Id", "t"."CreatedTime", "t"."WebsiteId"
FROM (
SELECT "c"."Id", "c"."CreatedTime", "c"."WebsiteId", ROW_NUMBER() OVER(PARTITION BY "c"."WebsiteId" ORDER BY "c"."CreatedTime" DESC) AS "row"
FROM "CheckLogs" AS "c"
) AS "t"
WHERE "t"."row" <= 1
) AS "t0" ON "w"."Id" = "t0"."WebsiteId"
MATERIALIZE 1
CO-ROUTINE 4
SCAN TABLE CheckLogs AS c USING INDEX IX_CheckLogs_WebsiteId_CreatedTime
USE TEMP B-TREE FOR RIGHT PART OF ORDER BY
SCAN SUBQUERY 4
SCAN TABLE Websites AS w
SEARCH SUBQUERY 1 AS t USING AUTOMATIC COVERING INDEX (WebsiteId=?)
这可以用 Index 解决吗?如果没有,是否有一种有效的方法来查询它而不创建 N+1 查询?我试图想办法用 2 个查询来做到这一点,但想不出任何更好的方法来像 EF Core 那样翻译它)。
另外,我认为这是一个非常常见的问题,但我不知道应该使用什么关键字来找到此类问题的解决方案。我对此类问题的通用解决方案没有意见(即获取Categories 列表中的最新Product)。谢谢。
我将 EF Core 用于 DB Schema:
public class Website
{
public int Id { get; set; }
// Other properties
public ICollection<CheckLog> CheckLogs { get; set; }
}
[Index(nameof(CreatedTime))]
[Index(nameof(WebsiteId), nameof(CreatedTime))]
public class CheckLog
{
public int Id { get; set; }
public DateTime CreatedTime { get; set; }
public int WebsiteId { get; set; }
public Website Website { get; set; }
// Other properties
}
【问题讨论】:
标签: sql .net sqlite indexing entity-framework-core