Skip to content
Go back

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

Published:  at  12:00 AM

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 中的命名查询过滤器:每个实体支持多个查询过滤器