在我们的系统中,我们在 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/