概要
本文提供一個EF Core的優(yōu)化案例,主要介紹一些EF Core常用的優(yōu)化方法,以及在優(yōu)化過程中,出現(xiàn)性能反復(fù)的時候的解決方法,并澄清一些對優(yōu)化概念的誤解,例如AsNoTracking并不包治百病。
本文使用的是Dotnet 6.0和EF Core 7.0。
代碼及實現(xiàn)
背景介紹
本文主要使用一個圖書和作者的案例,用于介紹優(yōu)化過程。
- 一個作者Author有多本自己寫的的圖書Book
- 一本圖書Book有一個發(fā)行商Publisher
- 一個作者Author是一個系統(tǒng)用戶User
- 一個系統(tǒng)用戶User有多個角色Role
本實例中Author表和Book數(shù)據(jù)量較大,記錄數(shù)量全部過萬條,其它數(shù)據(jù)表記錄大概都是幾十或幾百條。具體實體類定義請見附錄。
查詢需求
我們需要查找寫書最多的前兩名作家,該作家需要年齡在20歲以上,國籍是法國。需要他們的FirstName, LastName, Email,UserName以及在1900年以前他們發(fā)行的圖書信息,包括書名Name和發(fā)行日期Published。
基本優(yōu)化思路
本人做EF Core的復(fù)雜查詢優(yōu)化,并不推薦直接查看生成的SQL代碼,我習(xí)慣按照如下方式進行:
首先,進行EF的LINQ代碼檢查(初篩),找到明顯的錯誤。
- 查看代碼中是否有基本錯誤,主要針對全表載入的問題。例如EF需要每一步的LINQ擴展方法的返回值都是IQueryable類型,不能有IEnumerable類型;
- 查看是否有不需要的欄位;
- 根據(jù)情況決定是否加AsNoTracking,注意這個東西有時候加了也沒用;
其次,找到數(shù)據(jù)量較大的表,進行代碼整理和針對大數(shù)據(jù)表的優(yōu)化(精細化調(diào)整)
- 在操作大數(shù)據(jù)表時候,先要進行基本的過濾;
- 投影操作Select應(yīng)該放到排序操作后面;
- 減少返回值數(shù)量,推薦進行分頁操作;
本人推薦一旦出現(xiàn)性能反復(fù)的時候或者代碼整體基本完成的時候,再去查看生成的SQL代碼。
初始查詢代碼
public List<AuthorWeb> GetAuthors() {
using var dbContext = new AppDbContext();
var authors = dbContext.Authors
.Include(x => x.User)
.ThenInclude(x => x.UserRoles)
.ThenInclude(x => x.Role)
.Include(x => x.Books)
.ThenInclude(x => x.Publisher)
.ToList()
.Select(x => new AuthorWeb
{
UserCreated = x.User.Created,
UserEmailConfirmed = x.User.EmailConfirmed,
UserFirstName = x.User.FirstName,
UserLastActivity = x.User.LastActivity,
UserLastName = x.User.LastName,
UserEmail = x.User.Email,
UserName = x.User.UserName,
UserId = x.User.Id,
RoleId = x.User.UserRoles.FirstOrDefault(y => y.UserId == x.UserId).RoleId,
BooksCount = x.BooksCount,
AllBooks = x.Books.Select(y => new BookWeb
{
Id = y.Id,
Name = y.Name,
Published = y.Published,
ISBN = y.ISBN,
PublisherName = y.Publisher.Name
}).ToList(),
AuthorAge = x.Age,
AuthorCountry = x.Country,
AuthorNickName = x.NickName,
Id = x.Id
})
.ToList()
.Where(x => x.AuthorCountry == "France" && x.AuthorAge == 20)
.ToList();
var orderedAuthors = authors.OrderByDescending(x => x.BooksCount).ToList().Take(2).ToList();
List<AuthorWeb> finalAuthors = new List<AuthorWeb>();
foreach (var author in orderedAuthors)
{
List<BookWeb> books = new List<BookWeb>();
var allBooks = author.AllBooks;
foreach (var book in allBooks)
{
if (book.Published.Year < 1900)
{
book.PublishedYear = book.Published.Year;
books.Add(book);
}
}
author.AllBooks = books;
finalAuthors.Add(author);
}
return finalAuthors;
}
Benchmark測試后,系統(tǒng)資源使用情況如下:
代碼性能非常差,內(nèi)存消耗很大,一次執(zhí)行就要消耗190MB,執(zhí)行時間超過2s。如果是放到WebAPI里面調(diào)用,用戶會有明顯的卡頓感覺;如果面臨高并發(fā)的情況,很可得會造成服務(wù)器資源緊張,返回各種500錯誤。
優(yōu)化代碼
初篩
按照我們的優(yōu)化思路,在查看上面的代碼后,發(fā)現(xiàn)一個嚴(yán)重的問題。
雖然每次LINQ查詢返回都是IQueryable類型,但是源碼中有多個ToList(),尤其是第一個,它的意思是將Author, Book,User,Role,Publisher等多個數(shù)據(jù)表的數(shù)據(jù)全部載入,前面已經(jīng)說了,Author, Book兩張表的數(shù)據(jù)量很大,必然影響性能。
我們需要刪除前面多余的ToList(),只保留最后的即可。請參考附錄中的方法GetAuthors_RemoveToList()。
在GetAuthors_RemoveToList()基礎(chǔ)上,對照用戶的需求,發(fā)現(xiàn)查詢結(jié)果中包含了Role相關(guān)的信息和很多Id信息,但是查詢結(jié)果并不需要這些,因此必須刪掉。請參考附錄中的方法GetAuthorsOptimized_RemoveColumn()
在GetAuthorsOptimized_RemoveColumn的基礎(chǔ)上,我們再加入AsNoTracking方法。請參考附錄中的方法GetAuthorsOptimized_AsNoTracking()
我們在Benchmark中,測試上面提到的三個方法,直接結(jié)果如下:
從Benchmark的測試結(jié)果上看,刪除多余ToList方法和刪除多余的欄位,確實帶來了性能的大幅提升。
但是增加AsNoTracking,性能提反而下降了一點。這也說明了AsNoTracking并不是適用所有場景。Select投影操作生成的AuthorWeb對像,并不是EF管理的,與DbContext無關(guān),它只是作為前端API的返回值。相當(dāng)于EF做了沒有用的事,所以性能略有下降。
代碼進一步調(diào)整
初篩階段完成后,下面對代碼進一步整理
下面Take和Order操作可以并入基本的查詢中,Take可以幫助我們減少返回值的數(shù)量。請見 GetAuthorsOptimized_ChangeOrder()方法。
var orderedAuthors = authors.OrderByDescending(x => x.BooksCount).ToList().Take(2).ToList();
在GetAuthorsOptimized_ChangeOrder基礎(chǔ)上,對于dbContext.Authors,Author是一張數(shù)據(jù)量很大的表,我們需要在其進行聯(lián)表操作前,先過濾掉不需要的內(nèi)容,所以我們可以把Where前提,還有就是將排序操作放到投影的Select前面完成。請見 GetAuthorsOptimized_ChangeOrder方法。
上面的兩個優(yōu)化方法的執(zhí)行結(jié)果如下:
可以看到性略能有提升。
下面我們?yōu)榱诉M一步提升性能,可以查看一下生成的SQL代碼,看看是否還有優(yōu)化的空間。
GetAuthorsOptimized_ChangeOrder方法生成的SQL如下:
SELECT [u].[FirstName], [u].[LastName], [u].[Email], [u].[UserName], [t].[
BooksCount], [t].[Id], [u].[Id], [b].[Name], [b].[Published], [b].[Id], [t].[Age
], [t].[Country]
FROM (
SELECT TOP(@__p_0) [a].[Id], [a].[Age], [a].[BooksCount], [a].[Country
], [a].[UserId]
FROM [Authors] AS [a]
WHERE [a].[Country] = N'France' AND [a].[Age] >= 20
ORDER BY [a].[BooksCount] DESC
) AS [t]
INNER JOIN [Users] AS [u] ON [t].[UserId] = [u].[Id]
LEFT JOIN [Books] AS [b] ON [t].[Id] = [b].[AuthorId]
ORDER BY [t].[BooksCount] DESC, [t].[Id], [u].[Id]
從生成SQL來看,Author表在使用之前過濾掉了相關(guān)的內(nèi)容,但是直接Left Join了[Books]這個大表。我們可以按照前面提到的1900年以前的查詢要求,在左聯(lián)之前先過濾一下,請參考 GetAuthorsOptimized_SelectFilter方法。
該方法執(zhí)行后,生成的SQL如下:
SELECT [u].[FirstName], [u].[LastName], [u].[Email], [u].[UserName], [t].[
BooksCount], [t].[Id], [u].[Id], [t0].[Name], [t0].[Published], [t0].[Id], [t].[
Age], [t].[Country]
FROM (
SELECT TOP(@__p_1) [a].[Id], [a].[Age], [a].[BooksCount], [a].[Country
], [a].[UserId]
FROM [Authors] AS [a]
WHERE [a].[Country] = N'France' AND [a].[Age] >= 20
ORDER BY [a].[BooksCount] DESC
) AS [t]
INNER JOIN [Users] AS [u] ON [t].[UserId] = [u].[Id]
LEFT JOIN (
SELECT [b].[Name], [b].[Published], [b].[Id], [b].[AuthorId]
FROM [Books] AS [b]
WHERE [b].[Published] < @__date_0
) AS [t0] ON [t].[Id] = [t0].[AuthorId]
ORDER BY [t].[BooksCount] DESC, [t].[Id], [u].[Id]
在左聯(lián)之前,確實進行了過濾,該方法的性能測試如下:
在避免Book表直接進行左聯(lián)后,性能有所提升。
最后一個優(yōu)化點,是在EF Core 5.0里面提供了帶Filter功能的Include方法,也可以用于本案例的優(yōu)化,但是該特性但是存在一些局限性,具體請參考EF Core中帶過濾器參數(shù)的Include方法
但是此方法又涉及了將IQueryable轉(zhuǎn)換成IEnumerable的操作,最后要將生成的Author對象全部轉(zhuǎn)換成AuthorWeb對象。代碼過于繁瑣,而且?guī)淼男阅芴嵘膊幻黠@。因此放棄這個點。文章來源:http://www.zghlxwxcb.cn/news/detail-714797.html
dbContext.Authors
.AsNoTracking()
.Include(x => x.Books.Where(b => b.Published < date))
......
結(jié)論
從這個優(yōu)化過程來看,其實對性能提升最大的貢獻就是刪除多余的ToList(),避免全表載入和刪除不需要的欄位兩項。其它所謂更精細的優(yōu)化,性能提升有限。文章來源地址http://www.zghlxwxcb.cn/news/detail-714797.html
附錄
實體類定義
public class Author
{
public int Id { get; set; }
public int Age { get; set; }
public string Country { get; set; }
public int BooksCount { get; set; }
public string NickName { get; set; }
[ForeignKey("UserId")]
public User User { get; set; }
public int UserId { get; set; }
public virtual List<Book> Books { get; set; } = new List<Book>();
}
public class Book
{
public int Id { get; set; }
public string Name { get; set; }
[ForeignKey("AuthorId")]
public Author Author { get; set; }
public int AuthorId { get; set; }
public DateTime Published { get; set; }
public string ISBN { get; set; }
[ForeignKey("PublisherId")]
public Publisher Publisher { get; set; }
public int PublisherId { get; set; }
}
public class Publisher
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime Established { get; set; }
}
public class User
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public virtual List<UserRole> UserRoles { get; set; } = new List<UserRole>();
public DateTime Created { get; set; }
public bool EmailConfirmed { get; set; }
public DateTime LastActivity { get; set; }
}
public class Role
{
public int Id { get; set; }
public virtual List<UserRole> UserRoles { get; set; } = new List<UserRole>();
public string Name { get; set; }
}
public class AuthorWeb
{
public DateTime UserCreated { get; set; }
public bool UserEmailConfirmed { get; set; }
public string UserFirstName { get; set; }
public DateTime UserLastActivity { get; set; }
public string UserLastName { get; set; }
public string UserEmail { get; set; }
public string UserName { get; set; }
public int UserId { get; set; }
public int AuthorId { get; set; }
public int Id { get; set; }
public int RoleId { get; set; }
public int BooksCount { get; set; }
public List<BookWeb> AllBooks { get; set; }
public int AuthorAge { get; set; }
public string AuthorCountry { get; set; }
public string AuthorNickName { get; set; }
}
public class BookWeb
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime Published { get; set; }
public int PublishedYear { get; set; }
public string PublisherName { get; set; }
public string ISBN { get; set; }
}
優(yōu)化方法
[Benchmark]
public List<AuthorWeb> GetAuthors() {
using var dbContext = new AppDbContext();
var authors = dbContext.Authors
.Include(x => x.User)
.ThenInclude(x => x.UserRoles)
.ThenInclude(x => x.Role)
.Include(x => x.Books)
.ThenInclude(x => x.Publisher)
.ToList()
.Select(x => new AuthorWeb
{
UserCreated = x.User.Created,
UserEmailConfirmed = x.User.EmailConfirmed,
UserFirstName = x.User.FirstName,
UserLastActivity = x.User.LastActivity,
UserLastName = x.User.LastName,
UserEmail = x.User.Email,
UserName = x.User.UserName,
UserId = x.User.Id,
RoleId = x.User.UserRoles.FirstOrDefault(y => y.UserId == x.UserId).RoleId,
BooksCount = x.BooksCount,
AllBooks = x.Books.Select(y => new BookWeb
{
Id = y.Id,
Name = y.Name,
Published = y.Published,
ISBN = y.ISBN,
PublisherName = y.Publisher.Name
}).ToList(),
AuthorAge = x.Age,
AuthorCountry = x.Country,
AuthorNickName = x.NickName,
Id = x.Id
})
.ToList()
.Where(x => x.AuthorCountry == "France" && x.AuthorAge >= 20)
.ToList();
var orderedAuthors = authors.OrderByDescending(x => x.BooksCount).ToList().Take(2).ToList();
List<AuthorWeb> finalAuthors = new List<AuthorWeb>();
foreach (var author in orderedAuthors)
{
List<BookWeb> books = new List<BookWeb>();
var allBooks = author.AllBooks;
foreach (var book in allBooks)
{
if (book.Published.Year < 1900)
{
book.PublishedYear = book.Published.Year;
books.Add(book);
}
}
author.AllBooks = books;
finalAuthors.Add(author);
}
return finalAuthors;
}
[Benchmark]
public List<AuthorWeb> GetAuthors_RemoveToList()
{
using var dbContext = new AppDbContext();
var authors = dbContext.Authors
.Include(x => x.User)
.ThenInclude(x => x.UserRoles)
.ThenInclude(x => x.Role)
.Include(x => x.Books)
.ThenInclude(x => x.Publisher)
// .ToList()
.Select(x => new AuthorWeb
{
UserCreated = x.User.Created,
UserEmailConfirmed = x.User.EmailConfirmed,
UserFirstName = x.User.FirstName,
UserLastActivity = x.User.LastActivity,
UserLastName = x.User.LastName,
UserEmail = x.User.Email,
UserName = x.User.UserName,
UserId = x.User.Id,
RoleId = x.User.UserRoles.FirstOrDefault(y => y.UserId == x.UserId).RoleId,
BooksCount = x.BooksCount,
AllBooks = x.Books.Select(y => new BookWeb
{
Id = y.Id,
Name = y.Name,
Published = y.Published,
ISBN = y.ISBN,
PublisherName = y.Publisher.Name
}).ToList(),
AuthorAge = x.Age,
AuthorCountry = x.Country,
AuthorNickName = x.NickName,
Id = x.Id
})
// .ToList()
.Where(x => x.AuthorCountry == "France" && x.AuthorAge >=20)
.ToList();
var orderedAuthors = authors.OrderByDescending(x => x.BooksCount).ToList().Take(2).ToList();
List<AuthorWeb> finalAuthors = new List<AuthorWeb>();
foreach (var author in orderedAuthors)
{
List<BookWeb> books = new List<BookWeb>();
var allBooks = author.AllBooks;
foreach (var book in allBooks)
{
if (book.Published.Year < 1900)
{
book.PublishedYear = book.Published.Year;
books.Add(book);
}
}
author.AllBooks = books;
finalAuthors.Add(author);
}
return finalAuthors;
}
[Benchmark]
public List<AuthorWeb> GetAuthorsOptimized_RemoveColumn()
{
using var dbContext = new AppDbContext();
var authors = dbContext.Authors
// .Include(x => x.User)
//.ThenInclude(x => x.UserRoles)
// .ThenInclude(x => x.Role)
// .Include(x => x.Books)
// .ThenInclude(x => x.Publisher)
.Select(x => new AuthorWeb
{
// UserCreated = x.User.Created,
// UserEmailConfirmed = x.User.EmailConfirmed,
UserFirstName = x.User.FirstName,
// UserLastActivity = x.User.LastActivity,
UserLastName = x.User.LastName,
UserEmail = x.User.Email,
UserName = x.User.UserName,
// UserId = x.User.Id,
// RoleId = x.User.UserRoles.FirstOrDefault(y => y.UserId == x.UserId).RoleId,
BooksCount = x.BooksCount,
AllBooks = x.Books.Select(y => new BookWeb
{
// Id = y.Id,
Name = y.Name,
Published = y.Published,
// ISBN = y.ISBN,
// PublisherName = y.Publisher.Name
}).ToList(),
AuthorAge = x.Age,
AuthorCountry = x.Country,
AuthorNickName = x.NickName,
// Id = x.Id
})
.Where(x => x.AuthorCountry == "France" && x.AuthorAge >=20)
.ToList();
var orderedAuthors = authors.OrderByDescending(x => x.BooksCount).ToList().Take(2).ToList();
List<AuthorWeb> finalAuthors = new List<AuthorWeb>();
foreach (var author in orderedAuthors)
{
List<BookWeb> books = new List<BookWeb>();
var allBooks = author.AllBooks;
foreach (var book in allBooks)
{
if (book.Published.Year < 1900)
{
book.PublishedYear = book.Published.Year;
books.Add(book);
}
}
author.AllBooks = books;
finalAuthors.Add(author);
}
return finalAuthors;
}
[Benchmark]
public List<AuthorWeb> GetAuthorsOptimized_AsNoTracking()
{
using var dbContext = new AppDbContext();
var authors = dbContext.Authors
.AsNoTracking()
// .Include(x => x.User)
// .ThenInclude(x => x.UserRoles)
// .ThenInclude(x => x.Role)
// .Include(x => x.Books)
// .ThenInclude(x => x.Publisher)
.Select(x => new AuthorWeb
{
//UserCreated = x.User.Created,
// UserEmailConfirmed = x.User.EmailConfirmed,
UserFirstName = x.User.FirstName,
// UserLastActivity = x.User.LastActivity,
UserLastName = x.User.LastName,
UserEmail = x.User.Email,
UserName = x.User.UserName,
// UserId = x.User.Id,
//RoleId = x.User.UserRoles.FirstOrDefault(y => y.UserId == x.UserId).RoleId,
BooksCount = x.BooksCount,
AllBooks = x.Books.Select(y => new BookWeb
{
// Id = y.Id,
Name = y.Name,
Published = y.Published,
//ISBN = y.ISBN,
//PublisherName = y.Publisher.Name
}).ToList(),
AuthorAge = x.Age,
AuthorCountry = x.Country,
//AuthorNickName = x.NickName,
Id = x.Id
})
.Where(x => x.AuthorCountry == "France" && x.AuthorAge >=20)
.ToList();
var orderedAuthors = authors.OrderByDescending(x => x.BooksCount).ToList().ToList();
List<AuthorWeb> finalAuthors = new List<AuthorWeb>();
foreach (var author in authors)
{
List<BookWeb> books = new List<BookWeb>();
var allBooks = author.AllBooks;
foreach (var book in allBooks)
{
if (book.Published.Year < 1900)
{
book.PublishedYear = book.Published.Year;
books.Add(book);
}
}
author.AllBooks = books;
finalAuthors.Add(author);
}
return finalAuthors;
}
[Benchmark]
public List<AuthorWeb> GetAuthorsOptimized_Take_Order()
{
using var dbContext = new AppDbContext();
var authors = dbContext.Authors
.AsNoTracking()
.Select(x => new AuthorWeb
{
UserFirstName = x.User.FirstName,
UserLastName = x.User.LastName,
UserEmail = x.User.Email,
UserName = x.User.UserName,
BooksCount = x.BooksCount,
AllBooks = x.Books.Select(y => new BookWeb
{
Name = y.Name,
Published = y.Published,
}).ToList(),
AuthorAge = x.Age,
AuthorCountry = x.Country,
AuthorNickName = x.NickName,
})
.Where(x => x.AuthorCountry == "France" && x.AuthorAge >=20)
.OrderByDescending(x => x.BooksCount)
.Take(2)
.ToList();
// var orderedAuthors = authors.OrderByDescending(x => x.BooksCount).ToList().ToList();
List<AuthorWeb> finalAuthors = new List<AuthorWeb>();
foreach (var author in authors)
{
List<BookWeb> books = new List<BookWeb>();
var allBooks = author.AllBooks;
foreach (var book in allBooks)
{
if (book.Published.Year < 1900)
{
book.PublishedYear = book.Published.Year;
books.Add(book);
}
}
author.AllBooks = books;
finalAuthors.Add(author);
}
return finalAuthors;
}
[Benchmark]
public List<AuthorWeb> GetAuthorsOptimized_ChangeOrder()
{
using var dbContext = new AppDbContext();
var authors = dbContext.Authors
.AsNoTracking()
.Where(x => x.Country == "France" && x.Age >=20)
.OrderByDescending(x => x.BooksCount)
// .Include(x => x.User)
// .ThenInclude(x => x.UserRoles)
// .ThenInclude(x => x.Role)
// .Include(x => x.Books)
// .ThenInclude(x => x.Publisher)
.Select(x => new AuthorWeb
{
//UserCreated = x.User.Created,
// UserEmailConfirmed = x.User.EmailConfirmed,
UserFirstName = x.User.FirstName,
// UserLastActivity = x.User.LastActivity,
UserLastName = x.User.LastName,
UserEmail = x.User.Email,
UserName = x.User.UserName,
// UserId = x.User.Id,
//RoleId = x.User.UserRoles.FirstOrDefault(y => y.UserId == x.UserId).RoleId,
BooksCount = x.BooksCount,
AllBooks = x.Books.Select(y => new BookWeb
{
// Id = y.Id,
Name = y.Name,
Published = y.Published,
//ISBN = y.ISBN,
//PublisherName = y.Publisher.Name
}).ToList(),
AuthorAge = x.Age,
AuthorCountry = x.Country,
//AuthorNickName = x.NickName,
Id = x.Id
})
.Take(2)
.ToList();
// var orderedAuthors = authors.OrderByDescending(x => x.BooksCount).ToList().ToList();
List<AuthorWeb> finalAuthors = new List<AuthorWeb>();
foreach (var author in authors)
{
List<BookWeb> books = new List<BookWeb>();
var allBooks = author.AllBooks;
foreach (var book in allBooks)
{
if (book.Published.Year < 1900)
{
book.PublishedYear = book.Published.Year;
books.Add(book);
}
}
author.AllBooks = books;
finalAuthors.Add(author);
}
return finalAuthors;
}
// [Benchmark]
public List<AuthorWeb> GetAuthorsOptimized_IncludeFilter()
{
using var dbContext = new AppDbContext();
var date = new DateTime(1900, 1, 1);
var authors = dbContext.Authors
.AsNoTracking()
.Include(x => x.Books.Where(b => b.Published < date))
.Include(x => x.User)
// .IncludeFilter(x =>x.Books.Where(b =>b.Published.Year < 1900))
.Where(x => x.Country == "France" && x.Age >=20)
.OrderByDescending(x => x.BooksCount)
// .ThenInclude(x => x.UserRoles)
// .ThenInclude(x => x.Role)
// .Include(x => x.Books)
// .ThenInclude(x => x.Publisher)
.Take(2)
.ToList();
// var orderedAuthors = authors.OrderByDescending(x => x.BooksCount).ToList().ToList();
var authorList = authors.AsEnumerable().Select(x => new AuthorWeb
{
//UserCreated = x.User.Created,
// UserEmailConfirmed = x.User.EmailConfirmed,
UserFirstName = x.User.FirstName,
// UserLastActivity = x.User.LastActivity,
UserLastName = x.User.LastName,
UserEmail = x.User.Email,
UserName = x.User.UserName,
// UserId = x.User.Id,
//RoleId = x.User.UserRoles.FirstOrDefault(y => y.UserId == x.UserId).RoleId,
BooksCount = x.BooksCount,
AllBooks = x.Books
// .Where(b => b.Published < date)
.Select(y => new BookWeb
{
// Id = y.Id,
Name = y.Name,
Published = y.Published,
//ISBN = y.ISBN,
//PublisherName = y.Publisher.Name
}).ToList(),
AuthorAge = x.Age,
AuthorCountry = x.Country,
//AuthorNickName = x.NickName,
// Id = x.Id
}).ToList();
return authorList;
}
[Benchmark]
public List<AuthorWeb> GetAuthorsOptimized_SelectFilter()
{
using var dbContext = new AppDbContext();
var date = new DateTime(1900, 1, 1);
var authors = dbContext.Authors
.AsNoTracking()
.Include(x => x.Books.Where(b => b.Published < date))
.Where(x => x.Country == "France" && x.Age >=20)
.OrderByDescending(x => x.BooksCount)
.Select(x => new AuthorWeb
{
//UserCreated = x.User.Created,
// UserEmailConfirmed = x.User.EmailConfirmed,
UserFirstName = x.User.FirstName,
// UserLastActivity = x.User.LastActivity,
UserLastName = x.User.LastName,
UserEmail = x.User.Email,
UserName = x.User.UserName,
// UserId = x.User.Id,
//RoleId = x.User.UserRoles.FirstOrDefault(y => y.UserId == x.UserId).RoleId,
BooksCount = x.BooksCount,
AllBooks = x.Books
.Where(b => b.Published < date)
.Select(y => new BookWeb
{
// Id = y.Id,
Name = y.Name,
Published = y.Published,
//ISBN = y.ISBN,
//PublisherName = y.Publisher.Name
}).ToList(),
AuthorAge = x.Age,
AuthorCountry = x.Country,
//AuthorNickName = x.NickName,
// Id = x.Id
})
.Take(2)
.ToList();
return authors;
}
到了這里,關(guān)于一個Entity Framework Core的性能優(yōu)化案例的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!