{"id":2423,"date":"2025-08-27T17:21:00","date_gmt":"2025-08-27T17:21:00","guid":{"rendered":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2025\/08\/27\/efcore-visualizer-view-entity-framework-core-query-plan-inside-visual-studio\/"},"modified":"2025-08-27T17:21:00","modified_gmt":"2025-08-27T17:21:00","slug":"efcore-visualizer-view-entity-framework-core-query-plan-inside-visual-studio","status":"publish","type":"post","link":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2025\/08\/27\/efcore-visualizer-view-entity-framework-core-query-plan-inside-visual-studio\/","title":{"rendered":"EFCore.Visualizer \u2013 View Entity Framework Core query plan inside Visual Studio"},"content":{"rendered":"<p>This is a guest blog from <a href=\"https:\/\/github.com\/Giorgi\">Giorgi Dalakishvili<\/a>, the developer of <a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=GiorgiDalakishvili.EFCoreVisualizer\">EFCore.Visualizer<\/a>.<\/p>\n<p>Entity Framework Core is a powerful, feature-rich ORM powering many of today\u2019s applications. With EF Core, developers write strongly-typed LINQ queries that the framework translates into SQL queries for the target database. With advanced features such as including nested collections and lazy loading, Entity Framework Core frees developers from writing boilerplate data access code.<\/p>\n<h2>The Problem<\/h2>\n<p>While LINQ queries are typically translated to well-performing SQL queries, as schemas become larger and queries more complex, the generated SQL can become suboptimal. Missing database indexes can also cause queries to execute slowly, leading to degraded application performance.<\/p>\n<p>EF Core provides an easy way to <a href=\"https:\/\/learn.microsoft.com\/ef\/core\/logging-events-diagnostics\/#simple-logging\">log generated queries<\/a> and <a href=\"https:\/\/learn.microsoft.com\/ef\/core\/performance\/performance-diagnosis?tabs=simple-logging%2Cload-entities#identifying-slow-database-commands-via-logging\">identify slow queries<\/a>. This might be enough sometimes but to really get to the root of the problem and see how the database engine executes queries, it\u2019s necessary to explore the <a href=\"https:\/\/learn.microsoft.com\/sql\/relational-databases\/performance\/execution-plans?view=sql-server-ver17\">query execution plan<\/a>.<\/p>\n<h2>The Solution<\/h2>\n<p><a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=GiorgiDalakishvili.EFCoreVisualizer\">EFCore.Visualizer<\/a> is a Visual Studio extension for viewing and analyzing query plans directly inside Visual Studio. The extension adds a debugger visualizer for IQueryable&lt;&gt; variables that shows both the generated query and its execution plan.<\/p>\n<p>When you hit a breakpoint and hover over any IQueryable variable, EFCore.Visualizer captures the query, requests the execution plan from your database, and shows a visual representation of the query plan. The visualizer works with any EF Core query, whether it\u2019s a simple Where clause or a complex query with joins, includes, and aggregations. The extension supports every major RDBMS: SQL Server, PostgreSQL, MySQL, SQLite, and Oracle, automatically detecting your database provider.<\/p>\n<p>By bringing the query plan directly inside Visual Studio, it removes the need to switch between Visual Studio and the database management tool for viewing query plans and shortens the developer inner loop. Instead of copying the query from Visual Studio to database management tool, analyzing the execution plan, switching back, tweaking the query and repeating the above steps again, developers can view the query plan in Visual Studio right where they write and debug their code.<\/p>\n<h2>Installation<\/h2>\n<p>Getting started with EFCore.Visualizer is straightforward. You can install the extension directly from within Visual Studio by searching for \u201cEFCore.Visualizer\u201d in the Extension Manager. Alternatively, you can download it from the <a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=GiorgiDalakishvili.EFCoreVisualizer\">Visual Studio Marketplace<\/a>.<\/p>\n<h2>Usage<\/h2>\n<p>To demonstrate the extension usage, I will use the following model:<\/p>\n<p>public class BloggingContext : DbContext<br \/>\n{<br \/>\n    public DbSet&lt;Blog&gt; Blogs { get; set; }<br \/>\n    public DbSet&lt;Post&gt; Posts { get; set; }<\/p>\n<p>    protected override void OnModelCreating(ModelBuilder modelBuilder)<br \/>\n    {<br \/>\n        base.OnModelCreating(modelBuilder);<br \/>\n        modelBuilder.Entity&lt;Post&gt;().HasIndex(p =&gt; p.PublishedAt);<br \/>\n    }<br \/>\n}<\/p>\n<p>public class Blog<br \/>\n{<br \/>\n    public int BlogId { get; set; }<br \/>\n    public string Url { get; set; }<\/p>\n<p>    public List&lt;Post&gt; Posts { get; } = new();<br \/>\n}<\/p>\n<p>public class Post<br \/>\n{<br \/>\n    public int PostId { get; set; }<br \/>\n    public string Title { get; set; }<br \/>\n    public string Content { get; set; }<\/p>\n<p>    public DateTimeOffset PublishedAt { get; set; }<\/p>\n<p>    public int BlogId { get; set; }<br \/>\n    public Blog Blog { get; set; }<br \/>\n}<\/p>\n<p>The sample database has a couple of thousand rows in the Posts table.<\/p>\n<p>Once installed, start debugging and hover over any IQueryable instance. In the standard debugger tooltip click <strong>Query Plan Visualizer<\/strong> and view the generated SQL and the execution plan.<\/p>\n<p>Let\u2019s start by writing a query to get all posts written in 2010 and examining its execution plan:<\/p>\n<p>var postsQuery = bloggingContext.Posts.Where(post =&gt; post.PublishedAt.Year == 2010);<\/p>\n<p>You can see that even though there is an index on the PublishedAt column, SQL Server doesn\u2019t use it. If you look at the generated query, you will notice that the query is extracting the year from PublishedAt column making the query <a href=\"https:\/\/en.wikipedia.org\/wiki\/Sargable\">non-sargable<\/a>.<\/p>\n<p>Let\u2019s rewrite the query without changing the semantics and see what execution plan looks like:<\/p>\n<p>var fromDate = new DateTime(2010, 1, 1);<br \/>\nvar toDate = new DateTime(2011, 1, 1);<\/p>\n<p>postsQuery = bloggingContext.Posts.Where(post =&gt; post.PublishedAt &gt;= fromDate &amp;&amp; post.PublishedAt &lt; toDate);<\/p>\n<p>As you can see, with a simple change to the query, the database is now utilizing the index on the PublishedAt.<\/p>\n<h2>How it works<\/h2>\n<p>The visualizer works by turning the LINQ queries into ADO.NET commands and fetching its plan from the database engine. The plan is then rendered using the <a href=\"https:\/\/github.com\/JustinPealing\/html-query-plan\">html-query-plan<\/a> library for SQL Server, <a href=\"https:\/\/github.com\/dalibo\/pev2\/\">pev2<\/a> for Postgres or <a href=\"https:\/\/github.com\/dumptyd\/treeflex\">treeflex<\/a> for other databases.<\/p>\n<h2>Limitations<\/h2>\n<p>The visualizer doesn\u2019t support queries when a reducing terminating operator is used (Count(), Min(), First() etc). Also, if the query is very complex or the network connection to the database engine is slow, fetching the query plan can exceed the 5 second limit for custom visualizers. Unfortunately, there is no way to extend the timeout but you can vote for the <a href=\"https:\/\/github.com\/microsoft\/VSExtensibility\/issues\/325\">issue<\/a>.<\/p>\n<h2>Conclusion<\/h2>\n<p>As developers, we\u2019ve all been there \u2013 staring at a slow query wondering what the database is actually doing. If you\u2019re working with Entity Framework Core and want to better understand your query performance, give <a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=GiorgiDalakishvili.EFCoreVisualizer\">EFCore.Visualizer<\/a> a try. The source code is available on <a href=\"https:\/\/github.com\/Giorgi\/EFCore.Visualizer\">GitHub<\/a> if you\u2019d like to contribute or explore how it works.<\/p>\n<p>The post <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/ef-core-visualizer-view-entity-framework-core-query-plan-inside-visual-studio\/\">EFCore.Visualizer \u2013 View Entity Framework Core query plan inside Visual Studio<\/a> appeared first on <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\">.NET Blog<\/a>.<\/p>","protected":false},"excerpt":{"rendered":"<p>This is a guest blog from Giorgi Dalakishvili, the developer of EFCore.Visualizer. Entity Framework Core is a powerful, feature-rich ORM [&hellip;]<\/p>\n","protected":false},"author":0,"featured_media":0,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[7],"tags":[],"class_list":["post-2423","post","type-post","status-publish","format-standard","hentry","category-dotnet"],"_links":{"self":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/2423","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/comments?post=2423"}],"version-history":[{"count":0,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/2423\/revisions"}],"wp:attachment":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/media?parent=2423"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/categories?post=2423"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/tags?post=2423"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}