EntityFramework Core不得不注意的效能優化意外收穫,你會用錯?
前言
這兩天在著實研究EF Core專案當中對於一些查詢也沒實際去檢測,於是想著利用放假時間去實際測試下,結果本文就出來了,too young,too simple,後續博主會從底層翻譯表示式樹弄起,來從源頭瞭解EF Core
,通過本文你會明白不是EF Core
團隊沒做效能優化,而是你根本就沒用過而且正在倒退。
EntityFramework Core效能優化初探
簡單粗暴直接上程式碼,給出上下文以及需要用到的測試類,如下:
public class EFCoreContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseSqlServer(@"Server=.;Database=EFCoreDb;Trusted_Connection=True;");
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>(pc =>
{
pc.ToTable("Blog").HasKey(k => k.Id);
pc.Property(p => p.Name).IsRequired();
pc.Property(p => p.Url).IsRequired();
pc.Property(p => p.Count).IsRequired();
pc.Property(p => p.RowVersion).IsRequired().IsRowVersion().ValueGeneratedOnAddOrUpdate();
});
}
}
你是否像如下去獲取分頁資料呢,我們來一起瞧瞧:
var ef = new EFCoreContext();
var blogs = ef.Blogs;
var example1 = blogs
.Skip(1)
.Take(1)
.ToList();
var example2 = blogs
.Skip(10)
.Take(10)
.ToList();
我們通過如下SQL語句來檢視查詢計劃生成的SQL語句:
SELECT
sys.syscacheobjects.cacheobjtype,
sys.dm_exec_query_stats.execution_count,
sys.syscacheobjects.SQL,
sys.dm_exec_query_plan.query_plan
FROM sys.dm_exec_query_stats
INNER JOIN sys.dm_exec_cached_plans
ON sys.dm_exec_cached_plans.plan_handle = sys.dm_exec_query_stats.plan_handle
INNER JOIN sys.syscacheobjects ON sys.syscacheobjects.bucketid = sys.dm_exec_cached_plans.bucketid
CROSS APPLY sys.dm_exec_query_plan(sys.dm_exec_query_stats.plan_handle)
結果如下:
我們再來看看xml檔案中生成的SQL語句是怎樣的。
這說明什麼問題呢,上述查詢計劃中生成的SQL語句對於我們上述去取資料首選從第二條取一條,接下來是去取第十條後的十條,同時上述SQL語句而是宣告瞭兩個變數,換言之,上述兩條語句查詢最終在第一次查詢後SQL查詢計劃進行了快取,下次再去取資料時直接呼叫此SQL語句以此達到重用的目的,下面要是我們進行如下改造,結果會怎樣呢?
var ef = new EFCoreContext();
var blogs = ef.Blogs;
var count = 1;
var example1 = blogs
.Skip(count)
.Take(count)
.ToList();
count = 10;
var example2 = blogs
.Skip(count)
.Take(count)
.ToList();
結果經過上述改造利用變數的形式和直接賦值的形式是一致的,沒有什麼可講的,下面我們再來講述另外一種情況。請繼續往下看。
var ef = new EFCoreContext();
var blogs = ef.Blogs;
var skipTakeWithInt1 = blogs
.OrderBy(b => b.Id).Where(d => d.Name.Length > 1).ToList();
var skipTakeWithInt2 = blogs
.OrderBy(b => b.Id).Where(d => d.Name.Length > 10).ToList();
看出什麼沒有,對於上述兩條查詢則是對應進行了兩次SQL查詢,這下意識到了其中玄機了吧,下面我們將上述再改造一下:
var ef = new EFCoreContext();
var blogs = ef.Blogs;
var length = 1;
var skipTakeWithVariable1 = blogs
.OrderBy(b => b.Id).Where(d => d.Name.Length > length).ToList();
length = 10;
var skipTakeWithVariable2 = blogs
.OrderBy(b => b.Id).Where(d => d.Name.Length > length).ToList();
我們利用變數替換值改造後結果生成的SQL
語句與上述截然不同,這裡同樣是宣告瞭長度的變數,你發現沒該變數居然和我們宣告的變數長度是一致的,有點神奇,如此這樣通過變數替換值得方式來達到SQL
查詢計劃重用的目的,說到這裡,我們是不是應該回答一下為什麼會有這樣的情況發生呢。很多東西當你一直沒用到時就覺得不會用到壓根不用學,其實不然,比如這樣,其本質到底是怎樣的呢,其實是因為前面我已經講過【閉包】的原因。
lambda
表示式對我們宣告的變數進行了捕獲然後延長了其生命週期,也就是說將變數類似變成類中一個欄位了,類似如下:
[CompilerGenerated]
public sealed class ExampleClass1
{
public int Length;
}
[CompilerGenerated]
public sealed class ExampleClass2
{
public int Length;
}
自動編譯生成兩個類同時存在兩個對於長度的欄位。接下來當我們利用變數進行查詢就演變了如下這樣:
var ef = new EFCoreContext();
var blogs = ef.Blogs;
var length = 1;
var example1 = new ExampleClass1() { Length = length };
var skipTakeWithVariable1 = blogs
.OrderBy(b => b.Id).Where(d => d.Name.Length > example1.Length).ToList();
length = 10;
var example2 = new ExampleClass2() { Length = length };
var skipTakeWithVariable2 = blogs
.OrderBy(b => b.Id).Where(d => d.Name.Length > example2.Length).ToList();
這樣就很明瞭了為什麼通過變數達到查詢計劃重用的目的。
總結
關於EntityFramework Core
雖然目前設計的效能非常好,但是有些東西等我們去用時還得多加驗證,看其背後的本質是怎樣的,才能不會心生疑竇,到底該怎樣用,如何用,心中要有定數才是,一點一滴的細小優化不注意最終將導致大意失荊州。接下來博主會在三個方向不定時更新部落格,第一個是SQL Server
效能優化系列,第二個是ASP.NET Core MVC/WebAPi
,第三個則是EntityFramework Core
原理解析,敬請期待。
相關文章
- EntityFramework優化:查詢效能Framework優化
- 不得不提的前端效能優化前端優化
- 工作間隙整理學習內容的意外收穫
- 花5分鐘時間來了解一下高效能閘道器Kong會有意外收穫
- 【前端詞典】和媳婦講代理後的意外收穫前端
- 誤入 GitHub 遊戲區,意外地收穫頗豐Github遊戲
- EntityFramework 優化建議Framework優化
- EntityFramework使用及優化Framework優化
- EntityFramework優化:查詢WITH(NOLOCK)Framework優化
- 你真的瞭解EF嗎?關於EntityFramework的高階優化Framework優化
- 真實性——簡歷書寫你不得不注意的至上準則
- Event Loop事件迴圈,看完你總會有點收穫!OOP事件
- EntityFramework優化:第一次啟動優化Framework優化
- EntityFramework Core健康檢查Framework
- EntityFramework Core 5.0 VS SQLBulkCopyFrameworkSQL
- [java][效能優化]java高階開發必會的50個效能優化Java優化
- 效能優化小冊 - 提高網頁響應速度:優化你的 CDN 效能優化網頁
- 【面經】面試官:做過效能優化的工作嗎?你會從哪些方面入手做效能優化呢?面試優化
- 網賺遊戲火了,但你卻不得不注意它背後的法律風險遊戲
- 你必須懂的前端效能優化前端優化
- 升級MySQL5.7,開發不得不注意的坑MySql
- null調整為not null default xxx,不得不注意的坑Null
- 安卓應用效能除錯和優化經驗分享安卓除錯優化
- ASP.NET Core 效能優化最佳實踐ASP.NET優化
- 談談你對前端效能優化的理解前端優化
- Spark 3.x Spark Core詳解 & 效能優化Spark優化
- 作為前端,你不得不知道的搜尋引擎優化前端優化
- [翻譯]EntityFramework Core 2.2 釋出Framework
- EntityFramework Core筆記:入門(1)Framework筆記
- 效能除錯:分析並優化 Go 程式除錯優化Go
- Vue 應用效能優化指南Vue優化
- 移動應用效能優化優化
- 看了這篇還不會Linux效能分析和優化,你來打我Linux優化
- 【前端效能優化】vue效能優化前端優化Vue
- 如何做好遊戲產品留存?看完這個也許你會有所收穫遊戲
- 2020年初在這些股票上投資100美元你會收穫多少?
- [效能優化] 使用 esbuild 為你的構建提速 ?優化UI
- Android效能優化——效能優化的難題總結Android優化