EF Core 使用編譯查詢提升性能

今天,我將向您展現這些EF Core中一個很酷的功能,經過使用顯式編譯的查詢,提升查詢性能。git

不過在介紹具體內容以前,須要說明一點,EF Core已經對錶達式的編譯使用了緩存;當您的代碼須要重用之前執行的查詢時,EF Core將使用哈希查找並從緩存中返回已編譯的查詢。github

關於這一點,您能夠查閱github上面的代碼QueryCompiler.cs數據庫

不過,您可能但願直接對查詢進行編譯,跳過哈希的計算和緩存查找。咱們能夠經過在EF靜態類中下面兩個方法來實現:緩存

這些方法容許您定義一個已編譯的查詢,而後經過調用一個委託調用它。函數

若是您對錶達式的哈希計算感興趣,能夠看一看它的實現,很是複雜,ExpressionEqualityComparer.cs性能

爲了不由於數據庫查詢產生測試結果的差別,咱們這裏使用內存數據庫,它開銷更小,同時也能夠避免數據庫優化執行計劃以及緩存所帶來的問題。測試

實體定義之前數據庫DbContext

定義實體優化

在這咱們定義一個Category實體類型,很是簡單,只有兩個屬性。ui

public class Category
    {
        public Guid Id { get; set; }
        public string Name { get; set; }
    }

數據庫DbContextspa

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倍的差距。若是您對這個功能感興趣,不防本身測試一下。

相關文章
相關標籤/搜索