c# - EF core QueryFilter 的性能问题

标签 c# sql entity-framework ef-core-2.0 ef-core-2.1

在我们的系统中,我们在 EF 核心中使用 QueryFilters 时遇到了性能问题。 问题是 EF 核心在 LEFT JOIN 内部进行过滤,而不是在其外部进行过滤。

生成的 SQL 看起来像这样:

SELECT [pom].[Id],
        [pom].[DeleteDate],
        [pom].[UpdateDate],
        [pom].[Version],
        [t].[Id],
        [t].[MandatorId],
        [t].[NetPriceAmount],
        [t].[NetPriceCurrencyIso4217Code]
FROM [externaldata].[PurchaseOfferMetadata] AS [pom]
    LEFT JOIN (
    SELECT [po].[Id],
            [po].[MandatorId],
            [po].[NetPriceAmount],
            [po].[NetPriceCurrencyIso4217Code]
    FROM [externaldata].[PurchaseOffer] AS [po]
    WHERE [po].[MandatorId] = 1
) AS [t] ON [pom].[Id] = [t].[Id]
WHERE [pom].[Id] IN 
    (CAST(3094411 AS bigint), 
    CAST(4757070 AS bigint), 
    CAST(4757112 AS bigint), 
    CAST(5571232 AS bigint))

有问题的部分是 WHERE [po].[MandatorId] = 1。 如果这是在第二个 WHERE 语句中,则查询运行得更快。

数据库模型配置如下:

modelBuilder.Entity<PurchaseOffer>()
      .HasQueryFilter(po => po.MandatorId == 1)
      .ToTable(nameof(PurchaseOffer), schema: ExternalDataSchemaName);

modelBuilder.Entity<PurchaseOfferMetadata>()
      .HasOne(pom => pom.PurchaseOffer)
      .WithOne(po => po.Metadata)
      .HasForeignKey<PurchaseOffer>(po => po.Id);

在数据库中我们设置了这样的外键:

IF OBJECT_ID('[externaldata].[FK_PurchaseOffer_PurchaseOfferMetadata]', 'F') IS NULL
BEGIN
    ALTER TABLE [externaldata].[PurchaseOffer] ADD CONSTRAINT [FK_PurchaseOffer_PurchaseOfferMetadata] FOREIGN KEY
    (
        [Id]
    )
    REFERENCES [externaldata].[PurchaseOfferMetadata] ([Id])
END;

EF 核心查询如下所示:

var existingPurchaseOfferMetadatasById = await db.PurchaseOfferMetadatas
   .Where(pom => purchaseOfferIds.Contains(pom.Id))
   .Include(pom => pom.PurchaseOffer)
   .ToDictionaryAsync(pom => pom.Id, cancellationToken);

目前我们在每个表中有以下数量的记录:

  • PurchaseOfferMetadata:12'654'639
  • 采购报价:1'689'634

有没有人也遇到过这个问题并且可能找到了解决方案?

最佳答案

EF 在历史上并没有在连接复杂时创建最优化的 SQL 查询方面做得很好。我无法回答您如何让 Linq 了解您的数据库优化设计;但是,如果您知道应该生成的 SQL,那么我建议为了更好的复杂 READ 性能,使用像 Dapper 这样的 NuGet 包。编写您想要的确切 SQL 并获得您的数据库应得的连接。

using Dapper;

[...]

public class SalsaZima
{
  public int ID { get; set; }
  public string MySalsaColumn { get; set; }
  public string MyZimaColumn { get; set; }
}

[...]

// get data from database
using (IDbConnection dp = Dapper)
{
  string query = @"SELECT 
                     s.ID
                    ,s.MySalsaColumn
                    ,z.MyZimaColumn
                   FROM dbo.Salsa s 
                   LEFT JOIN dbo.Zima z
                     ON s.ZimaID = z.ID";

  return dp.Query<SalsaZima>(query).ToList();
}

关于c# - EF core QueryFilter 的性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55238927/

相关文章:

c# - 在 IIS 中提供 DXF(和其他类型)文件

mysql 查询需要 13 分钟才能运行

sql - hibernate.hbm2ddl.auto 不会将序列链接到 id 列

c# - 一种搜索实体的方法,该实体的某个属性与 Entity Framework 中的给定条件匹配

c# - 比较 EF 时间戳值

c# - Redis C# 无法左推?

c# - ImageGalleryControl 未触发

javascript - 如何在 javascript 中过滤类似于此 SQL 查询中的 GroupBy 和having 的对象?

c# - Entity Framework ISNULL 在 Where 条件

c# - 从对 HttpWebRequest 的调用中复制 HTTP 请求/响应 header ?