前言:數據庫 :Sql Server2016
編輯器:VS2019
環境 :.net core 和efcore
數據量:5萬條
相關聯的表:3個相關表
!!!:這些表創建時沒有外鍵等相關連接,所以麻煩
需求:展示個人用戶所有所有的信息,數據分別存在大概5個表里面,有接近6萬人,查詢排列展示出來
吐槽:一開始搞了半天弄到5秒,不行!再改弄到3秒,還是不行!!最后壓縮到了1.4秒左右。這可能是目前我的極限了,如果有大佬有辦法 請!請!請! 給我留言說一下哪里還能優化
答案:
一般有FromSqlRaw 和FromSql,我們選FromSqlRaw來用,而FromSql在Efcore3.0中顯示已過時
DbContext.set<ResultList>.FromSqlRaw("select * from ...").ToList() //ResultList是實體類,在數據庫中是視圖.Tolist()必加
詳情往下看
一般來說我們在lamdba表達式中進行處理的時候,查詢處理多個表我實測三萬人要處理17分鍾左右(看電腦性能)
例子:以下都是簡寫,有說不通的地方那就對了,不重要,知道干嘛就行了
首先這些最終都是被存到了內存里面了,處理起來耗內存,而且這只是一個人查都占很大內存,
有人說可以不往內存里面存,但是那些排序取第一條,截取其中十幾條展示等等操作很難操作,照樣很慢
var Data = await _userServer.query().ToListAsync(); //所有的用戶 var File= await _fileServer.query().ToListAsync(); var Photo= await _photoServer.query().ToListAsync(); var Cert = await _certServer.query().ToListAsync(); var result = await Data.Select(x => new Filter { Id=x.Id, Name = x.Name, IdCard=x.IdCard, File= File.Where(y =>y.IdCard==x.IdCard).Select(t =>new Filter //文件有很多,取最新的一條 { Id=t.Id, Name=t.Name, CertCode=t.CertCode, }).OrderByDescending(t => t.Id).FirstOrDefault(), Photo = photo.Where(y =>y.IdCard==x.IdCard).Select(t => new Filter //照片也可以有很多張,取最新 { Id = t.Id, Name = t.Name, Photo=t.Photo, }).OrderByDescending(t => t.Id).FirstOrDefault(), Certs = _certService.Query(y => y.IdCard== x.IdCard).OrderByDescending(y => y.Id).FirstOrDefault(), }).OrderByDescending(x => x.Id).ToPagedListAsync(Page,PageSize);
看着上面的就很慢,而且,就是說幾萬條數據要在程序里面循環處理十幾萬次才能得出答案,
而最快的方法當然是 原生Sql語句 永遠的神
數據
WITH datas as //這里使用With為了加快sql運行速度,with為SQL片段,截取一塊來用 (select IdCard, Name from [dbo].[user] GROUP BY IdCard, Name) File as (select * from [dbo].[user]) select Data.Id, Data.Name, F.file, P.photo, C.Cert from datas left join File F //為什么要用left join 因為一個人對應的 文件 照片 證書 可能為空 on F.IdCard=datas.IdCard and F.name=datas.name left join ........ left join......... //懶得寫了,跟上一個一樣
現在數據庫就完成了,但是這樣雖然拼起來了我們查詢也有了,還有一個問題就是我們在后端用什么東西接收存起來
接收
.netcroe+Efcore 自定義類接收時候報錯,不能生成該類型文件得把類加到DbContext中才能正確生成接收
public class Db : DbContext { public CertMSDb(DbContextOptions<Db> options) : base(options) { } public virtual DbSet<File> Files{ get; set; } public virtual DbSet<Photo> Photos{ get; set; } public virtual DbSet<Cert> Certs{ get; set; } //我們得自己加一條不然不能直接接收我們的數據 public virtual DbSet<ResultList> ResultLists{ get; set; } } //這個類型就跟我們的取出來的值保持一致 public class ResultList { public int Id{get;set;} public int Name{get;set;} public int File{get;set;} public int Photo{get;set;} public int Cert{get;set;} }
完成后使用就簡單,可以簡寫
//一般我們使用 var Data = _userServer.query<ResultList>(); //或者 var data =DbContext.set<ResultList>(); //還有 var data =DbContext.set<ResultList>().FromSqlRaw("sql"); //直接使用 注意,加了s的實例后的名字 var data =DbContext.ResultLists.FromSqlRaw("sql").ToList(); //注意后面得加上ToList()或者其他的
上述為我處理的方式簡寫版本可能寫的改的有漏了,更多可以在這上面加其他功能