gpt4 book ai didi

performance - 在 Entity Framework LINQ 查询中使用 IEnumerable.Contains 时如何避免查询计划重新编译?

转载 作者:行者123 更新时间:2023-12-03 08:58:23 25 4
gpt4 key购买 nike

我使用 Entity Framework (v6.1.1) 执行了以下 LINQ 查询:

private IList<Customer> GetFullCustomers(IEnumerable<int> customersIds)
{
IQueryable<Customer> fullCustomerQuery = GetFullQuery();
return fullCustomerQuery.Where(c => customersIds.Contains(c.Id)).ToList();
}

这个查询被翻译成相当不错的 SQL:
SELECT 
[Extent1].[Id] AS [Id],
[Extent1].[FirstName] AS [FirstName]
-- ...
FROM [dbo].[Customer] AS [Extent1]
WHERE [Extent1].[Id] IN (1, 2, 3, 5)

但是,我在查询编译阶段受到了非常显着的性能影响。来电:
ELinqQueryState.GetExecutionPlan(MergeOption? forMergeOption) 

占用 时间的约 50%每个请求 .深入挖掘,结果发现每次我传递不同的客户 ID 时都会重新编译查询。
根据 MSDN article ,这是一种预期的行为,因为查询中使用的 IEnumerable 被认为是易失的,并且是缓存的 SQL 的一部分。这就是为什么对于 customerIds 的每个不同组合,SQL 都是不同的,并且它总是具有不同的哈希值,用于从缓存中获取已编译的查询。

现在的问题是: 如何在仍然使用多个customersId 进行查询的同时避免这种重新编译?

最佳答案

到目前为止,在使用 SQL Server 数据库提供程序时,这仍然是 Entity Framework Core 中的一个问题。
我写了QueryableValues解决this problem在一个灵活的 performant方式;有了它,您可以组合 IEnumerable<T> 中的值在您的查询中,就像它是您的 DbContext 中的另一个实体一样.
与其他解决方案相比,QueryableValues达到 performance 这个水平经过:

  • 通过到数据库的单次往返来解决。
  • 无论提供的值如何,都保留查询的执行计划。

  • 使用示例:
    // Sample values.
    IEnumerable<int> values = Enumerable.Range(1, 10);

    // Using a Join.
    var myQuery1 =
    from e in dbContext.MyEntities
    join v in dbContext.AsQueryableValues(values) on e.Id equals v
    select new
    {
    e.Id,
    e.Name
    };

    // Using Contains.
    var myQuery2 =
    from e in dbContext.MyEntities
    where dbContext.AsQueryableValues(values).Contains(e.Id)
    select new
    {
    e.Id,
    e.Name
    };
    您还可以组合复杂类型!
    它以 nuget package 的形式提供该项目可以找到 here .它是在 MIT 许可下分发的。
    benchmarks为自己说话。

    关于performance - 在 Entity Framework LINQ 查询中使用 IEnumerable.Contains 时如何避免查询计划重新编译?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25228362/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com