今天,我將向您展示這些EF Core中一個很酷的功能,通過使用顯式編譯的查詢,提高查詢性能。 不過在介紹具體內容之前,需要說明一點,EF Core已經對錶達式的編譯使用了緩存;當您的代碼需要重用以前執行的查詢時,EF Core將使用哈希查找並從緩存中返回已編譯的查詢。 關於這一點,您可以查閱gith ...
今天,我將向您展示這些EF Core中一個很酷的功能,通過使用顯式編譯的查詢,提高查詢性能。
不過在介紹具體內容之前,需要說明一點,EF Core已經對錶達式的編譯使用了緩存;當您的代碼需要重用以前執行的查詢時,EF Core將使用哈希查找並從緩存中返回已編譯的查詢。
關於這一點,您可以查閱github上面的代碼QueryCompiler.cs
不過,您可能希望直接對查詢進行編譯,跳過哈希的計算和緩存查找。我們可以通過在EF
靜態類中下麵兩個方法來實現:
這些方法允許您定義一個已編譯的查詢,然後通過調用一個委托調用它。
如果您對錶達式的哈希計算感興趣,可以看一看它的實現,非常複雜,ExpressionEqualityComparer.cs。
為了避免因為資料庫查詢產生測試結果的差異,我們這裡使用記憶體資料庫,它開銷更小,同時也可以避免資料庫優化執行計劃以及緩存所帶來的問題。
實體定義以前資料庫DbContext
定義實體
在這我們定義一個Category
實體類型,非常簡單,只有兩個屬性。
public class Category
{
public Guid Id { get; set; }
public string Name { get; set; }
}
資料庫DbContext
在FillCategories
方法中,將記憶體資料庫中增加三條記錄。
public class TestDbContext : DbContext
{
public TestDbContext(DbContextOptions<TestDbContext> options) : base(options)
{
}
public DbSet<Category> Categories { get; set; }
public void FillCategories()
{
var foodCategory = new Category {
Id = Guid.NewGuid(),
Name = "Food"
};
Categories.AddRange(foodCategory, new Category {
Id = Guid.NewGuid(),
Name = "Drinks"
}, new Category {
Id = Guid.NewGuid(),
Name = "Clothing"
}, new Category {
Id = Guid.NewGuid(),
Name = "Electronis"
});
SaveChanges(true);
}
}
測試代碼
public class CompileQueryTest
{
private Func<TestDbContext, Guid, Category> _getCategory =
EF.CompileQuery((TestDbContext context, Guid id) => context.Categories.FirstOrDefault(c => c.Id == id));
private readonly TestDbContext _dbContext;
public CompileQueryTest()
{
var options = new DbContextOptionsBuilder<TestDbContext>().UseInMemoryDatabase(Guid.NewGuid().ToString()).Options;
var context = new TestDbContext(options);
context.FillCategories();
_dbContext = context;
}
private readonly Guid _queryId = Guid.NewGuid();
[Benchmark]
public void CompiledQuery()
{
_ = _getCategory(_dbContext, _queryId);
}
[Benchmark]
public void UnCompiledQuery()
{
_ = _dbContext.Categories.FirstOrDefault(c => c.Id == _queryId);
}
}
為了更加接近測試結果,我們在構造函數中創建TestDbContext
對象以及填充資料庫。
測試結果
我們使用Benchmark.Net進行基準測試,測試結果如下:
Method | Mean | Error | StdDev |
---|---|---|---|
CompiledQuery | 10.59 us | 0.0580 us | 0.0543 us |
UnCompiledQuery | 79.55 us | 0.7860 us | 0.7353 us |
經過編譯的查詢比未編譯過的查詢存在接近8倍的差距。如果您對這個功能感興趣,不防自己測試一下。