Skip to content
Go back

EFCore.Visualizer – 在 Visual Studio 中查看 Entity Framework Core 查询计划

Entity Framework Core 是一个功能强大的 ORM 框架,为当今的许多应用程序提供动力。使用 EF Core,开发者可以编写强类型的 LINQ 查询,框架会将其转换为目标数据库的 SQL 查询。凭借高级功能如包含嵌套集合和延迟加载,Entity Framework Core 让开发者免于编写样板数据访问代码。

问题分析

虽然 LINQ 查询通常会被转换为性能良好的 SQL 查询,但随着模式变得更大、查询变得更复杂,生成的 SQL 可能会变得次优。缺少数据库索引也可能导致查询执行缓慢,从而降低应用程序性能。

EF Core 提供了一种简单的方法来记录生成的查询识别慢查询。这有时可能足够,但要真正找到问题的根源并了解数据库引擎如何执行查询,有必要探索查询执行计划

解决方案

EFCore.Visualizer 是一个 Visual Studio 扩展,用于在 Visual Studio 内部直接查看和分析查询计划。该扩展为 IQueryable<> 变量添加了调试器可视化器,显示生成的查询及其执行计划。

当您遇到断点并悬停在任何 IQueryable 变量上时,EFCore.Visualizer 会捕获查询,从数据库请求执行计划,并显示查询计划的可视化表示。可视化器适用于任何 EF Core 查询,无论是简单的 Where 子句还是包含连接、包含和聚合的复杂查询。该扩展支持每个主要的关系数据库管理系统:SQL Server、PostgreSQL、MySQL、SQLite 和 Oracle,会自动检测您的数据库提供程序。

通过将查询计划直接带入 Visual Studio,它消除了在 Visual Studio 和数据库管理工具之间切换以查看查询计划的需要,并缩短了开发者的内循环。开发者无需从 Visual Studio 复制查询到数据库管理工具、分析执行计划、切换回来、调整查询并重复上述步骤,而是可以在 Visual Studio 中直接查看查询计划,就在他们编写和调试代码的地方。

安装方法

开始使用 EFCore.Visualizer 非常简单。您可以通过在扩展管理器中搜索”EFCore.Visualizer”直接从 Visual Studio 内部安装扩展。或者,您可以从 Visual Studio Marketplace 下载它。

使用示例

为了演示扩展的使用,我将使用以下模型:

public class BloggingContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<Post>().HasIndex(p => p.PublishedAt);
    }
}

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    public List<Post> Posts { get; } = new();
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public DateTimeOffset PublishedAt { get; set; }

    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

示例数据库在 Posts 表中有几千行数据。

安装后,开始调试并悬停在任何 IQueryable 实例上。在标准调试器工具提示中点击”查询计划可视化器”并查看生成的 SQL 和执行计划。

让我们首先编写一个查询来获取 2010 年写的所有文章并检查其执行计划:

var postsQuery = bloggingContext.Posts.Where(post => post.PublishedAt.Year == 2010);

您可以看到,即使 PublishedAt 列上有索引,SQL Server 也不使用它。如果您查看生成的查询,您会注意到查询正在从 PublishedAt 列中提取年份,这使得查询变成非SARGABLE的。

让我们在不改变语义的情况下重写查询,看看执行计划是什么样子的:

var fromDate = new DateTime(2010, 1, 1);
var toDate = new DateTime(2011, 1, 1);

postsQuery = bloggingContext.Posts.Where(post => post.PublishedAt >= fromDate && post.PublishedAt < toDate);

如您所见,通过对查询的简单更改,数据库现在正在利用 PublishedAt 上的索引。

工作原理

可视化器的工作原理是将 LINQ 查询转换为 ADO.NET 命令,并从数据库引擎获取其计划。然后使用 html-query-plan 库为 SQL Server 渲染计划,使用 pev2 为 Postgres 渲染,或使用 treeflex 为其他数据库渲染。

限制

当使用减少终止操作符(Count()Min()First() 等)时,可视化器不支持查询。此外,如果查询非常复杂或到数据库引擎的网络连接很慢,获取查询计划可能会超过自定义可视化器的5秒限制。遗憾的是,没有办法延长超时时间,但您可以为这个 issue 投票。

总结

作为开发者,我们都经历过这种情况——盯着一个慢查询,想知道数据库实际在做什么。如果您正在使用 Entity Framework Core 并想更好地了解查询性能,请尝试 EFCore.Visualizer。如果您想贡献或探索它的工作原理,源代码可在 GitHub 上获取。

这个扩展是由 Giorgi Dalakishvili 开发的,它为 Entity Framework Core 开发者提供了一个强大的调试和性能优化工具。通过直接在 Visual Studio 中查看查询执行计划,开发者可以更快地识别和解决性能问题,提高应用程序的整体性能。

主要特性

对于使用 Entity Framework Core 的 .NET 开发者来说,EFCore.Visualizer 是一个不可或缺的调试和性能优化工具。它简化了查询性能分析的流程,让开发者能够更高效地优化数据库查询。


标签


Previous Post
Workleap 的 .NET 代码规范与最佳实践详解
Next Post
EF Core 10 中的命名查询过滤器:每个实体支持多个查询过滤器