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 的生成规则中可能存在的昂贵的性能陷阱。