EF Core中LINQ的Contains未转成IN导致SQLite查询过慢如何解决
问题原因
EF Core默认对可空类型的相等判断会自动补充OR 两边都为NULL的兼容逻辑,加上当前版本的EF Core对Contains的子查询翻译做了降级处理,最终生成了带额外NULL判断的EXISTS关联查询,导致索引无法命中,查询效率骤降。
解决方案
方案1:修改LINQ写法强制非空(推荐)
你的子查询已经过滤了JobID != null,可以显式告知EF Core查询结果不存在NULL值,避免生成额外兼容逻辑:
// 先查最近3个非空JobID,显式取可空类型的Value var recentJobIds = ServicesData .Where(y => y.JobID != null) .GroupBy(y => y.JobID) .OrderByDescending(y => y.Max(z => z.Time)) .Select(y => y.Key.Value) .Take(3); // 主查询也显式用JobID的Value匹配 var result = ServicesData .Where(x => recentJobIds.Contains(x.JobID.Value)) .OrderBy(x => x.Time) .ToList();
修改后EF Core会直接生成和原生写法一致的IN运算符查询,性能和原生SQL基本持平。
方案2:关闭EF Core空值兼容逻辑
如果你的项目不需要兼容C#和SQL的空值判断差异,可以在DbContext配置中关闭该行为:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .UseSqlite("你的数据库连接字符串") .UseRelationalNulls(); // 启用数据库原生空值比较规则,不生成额外NULL判断逻辑 }
配置后你原来的LINQ写法就会直接生成IN语法的SQL,无需修改业务代码。
方案3:直接执行原生SQL
对性能要求极高的场景可以直接在EF Core中执行手写的原生SQL:
var result = ServicesData .FromSqlRaw(@"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;") .ToList();
该方案性能和直接在SQLite中执行查询完全一致。
内容的提问来源于stack exchange,提问作者kofifus
相关产品推荐
相关产品推荐

