EF 核心翻译查询表单 SQL
EF core translate query form SQL
我 运行 在我的 sqlite DB 上有以下查询:
SELECT * FROM ServicesData
WHERE JobID IN (
SELECT JobID
FROM ServicesData
WHERE JObID IS NOT NULL
GROUP BY JobID
ORDER BY MAX(Time) DESC LIMIT 3
)
ORDER BY Time;
(这会获取最近 3 个工作的所有条目,请参阅 table 并在此处查看结果 )
运行 在 LinqPad 中对我的 sqlite 数据库的查询需要 0.02 秒。
我正在尝试将其转换为 EF Core 中的 linq-to-sql
我试过了:
ServicesData.Where(x => ServicesData
.Where(y => y.JobID!=null)
.GroupBy(y => y.JobID)
.OrderByDescending(y => y.Max(z => z.Time))
.Select(y => y.Key)
.Take(3)
.Contains(x.JobID)
)
这似乎给出了与上述 SQL 相同的正确结果
但是 LinqPad 显示以下 SQL:
SELECT *
FROM "ServicesData" AS "s"
WHERE EXISTS (
SELECT 1
FROM (
SELECT "s0"."JobID", MAX("s0"."Time") AS "c"
FROM "ServicesData" AS "s0"
WHERE "s0"."JobID" IS NOT NULL
GROUP BY "s0"."JobID"
ORDER BY MAX("s0"."Time") DESC
LIMIT 3
) AS "t"
WHERE ("t"."JobID" = "s"."JobID") OR ("t"."JobID" IS NULL AND "s"."JobID" IS NULL))
而且非常慢,需要 2.6 秒!
由于某些原因,contains
未转换为 IN
运算符
我做错了什么?
查询本身需要 2.6 秒,还是为 3 个结果作业取回实体所需的时间? EF 实体化实体需要时间,因此它永远不会像原始 SQL 吐出结果那样快。
不过,从那个查询来看,这部分似乎有点令人担忧:
OR ("t"."JobID" IS NULL AND "s"."JobID" IS NULL))
由于内部查询仅考虑不为空的作业 ID,因此上述语句不应改变结果,但老实说没有必要。 EF 生成 EXISTS
而不是 IN
子句在 SQL 代中相当常见,通常不会对性能造成明显影响。
你可以试试:
ServicesData.Where(x => x.JobID != null
&& ServicesData
.Where(y => y.JobID!=null)
.GroupBy(y => y.JobID)
.OrderByDescending(y => y.Max(z => z.Time))
.Select(y => y.Key)
.Take(3)
.Contains(x.JobID))
.OrderBy(x => x.Time);
我很好奇这是否会去除额外的 Null = Null 津贴。
EF 是一个有用的工具,但最终它需要生成 SQL 以涵盖许多可能的操作排列和组合,因此不能指望选择最有效的 SQL 在所有情况下。有时使用两个更简单的查询,或求助于显式生成的 SQL 语句/存储过程可能是合理的。
例如:
var jobIds = ServiceData.Where(x => x.JobID != null)
.GroupBy(x => x.JobID)
.OrderByDescending(x => x.Max(y => y.Time))
.Select(x => x.Key)
.Take(3)
.ToList();
var serviceData = ServiceData.Where(x => jobIds.Contains(x.JobId))
.OrderBy(x => x.Time)
.ToList();
这是一个权衡性能与可能以变通办法的形式引入复杂性的问题,以避免 EF 的生成规则中可能存在的昂贵的性能陷阱。
我 运行 在我的 sqlite DB 上有以下查询:
SELECT * FROM ServicesData
WHERE JobID IN (
SELECT JobID
FROM ServicesData
WHERE JObID IS NOT NULL
GROUP BY JobID
ORDER BY MAX(Time) DESC LIMIT 3
)
ORDER BY Time;
(这会获取最近 3 个工作的所有条目,请参阅 table 并在此处查看结果
运行 在 LinqPad 中对我的 sqlite 数据库的查询需要 0.02 秒。
我正在尝试将其转换为 EF Core 中的 linq-to-sql
我试过了:
ServicesData.Where(x => ServicesData
.Where(y => y.JobID!=null)
.GroupBy(y => y.JobID)
.OrderByDescending(y => y.Max(z => z.Time))
.Select(y => y.Key)
.Take(3)
.Contains(x.JobID)
)
这似乎给出了与上述 SQL 相同的正确结果
但是 LinqPad 显示以下 SQL:
SELECT *
FROM "ServicesData" AS "s"
WHERE EXISTS (
SELECT 1
FROM (
SELECT "s0"."JobID", MAX("s0"."Time") AS "c"
FROM "ServicesData" AS "s0"
WHERE "s0"."JobID" IS NOT NULL
GROUP BY "s0"."JobID"
ORDER BY MAX("s0"."Time") DESC
LIMIT 3
) AS "t"
WHERE ("t"."JobID" = "s"."JobID") OR ("t"."JobID" IS NULL AND "s"."JobID" IS NULL))
而且非常慢,需要 2.6 秒!
由于某些原因,contains
未转换为 IN
运算符
我做错了什么?
查询本身需要 2.6 秒,还是为 3 个结果作业取回实体所需的时间? EF 实体化实体需要时间,因此它永远不会像原始 SQL 吐出结果那样快。
不过,从那个查询来看,这部分似乎有点令人担忧:
OR ("t"."JobID" IS NULL AND "s"."JobID" IS NULL))
由于内部查询仅考虑不为空的作业 ID,因此上述语句不应改变结果,但老实说没有必要。 EF 生成 EXISTS
而不是 IN
子句在 SQL 代中相当常见,通常不会对性能造成明显影响。
你可以试试:
ServicesData.Where(x => x.JobID != null
&& ServicesData
.Where(y => y.JobID!=null)
.GroupBy(y => y.JobID)
.OrderByDescending(y => y.Max(z => z.Time))
.Select(y => y.Key)
.Take(3)
.Contains(x.JobID))
.OrderBy(x => x.Time);
我很好奇这是否会去除额外的 Null = Null 津贴。
EF 是一个有用的工具,但最终它需要生成 SQL 以涵盖许多可能的操作排列和组合,因此不能指望选择最有效的 SQL 在所有情况下。有时使用两个更简单的查询,或求助于显式生成的 SQL 语句/存储过程可能是合理的。
例如:
var jobIds = ServiceData.Where(x => x.JobID != null)
.GroupBy(x => x.JobID)
.OrderByDescending(x => x.Max(y => y.Time))
.Select(x => x.Key)
.Take(3)
.ToList();
var serviceData = ServiceData.Where(x => jobIds.Contains(x.JobId))
.OrderBy(x => x.Time)
.ToList();
这是一个权衡性能与可能以变通办法的形式引入复杂性的问题,以避免 EF 的生成规则中可能存在的昂贵的性能陷阱。