這段時間在項目中運用Entity Framework作為底層數(shù)據(jù)交互框架。一個字,爽。不僅提高了開發(fā)效率,省了很多代碼,而且數(shù)據(jù)庫也規(guī)范了很多。按照網(wǎng)上的一些教程初步學(xué)習(xí),然后實際運用了,再結(jié)合MVC ,開發(fā)一個模塊的增刪改查,那真是一個爽歪歪。但是,隨著項目不斷完善,數(shù)據(jù)表越來越多,關(guān)聯(lián)性也越來越復(fù)雜,問題也逐漸露出水面。首先最大的問題是數(shù)據(jù)查詢慢。有個影響點是Linq里的Count(),查閱了網(wǎng)上許多資料,都沒有好的解決方法。這個問題暫時不說,如果那位大師有良策,還不忘賜教。
影響查詢慢主要問題在于數(shù)據(jù)查詢,說白了不了解EF是如何執(zhí)行sql查詢的,什么時候進行sql查詢?以什么方式進行sql查詢的?
我做了一個demo,以微軟的Northwind作為數(shù)據(jù)庫,有個Customers表和Orders表,Orders表里有個字段CustomerID,是Customers表的外鍵。代碼如下:
1 NorthwindEntities db = new NorthwindEntities();2 var query = db.Customers.AsEnumerable();3 for (int idx = 0; idx < 2; idx++)4 {5 var customer = query.ElementAt(idx);6 var order = customer.Orders.FirstOrDefault();7 if (order != null)8 Console.WriteLine(order.OrderID);9 }在跟蹤代碼時,同時將SQL Server PRofiler打開。代碼執(zhí)行到2行,sql跟蹤器并沒有執(zhí)行sql語句。當(dāng)執(zhí)行第5行時,sql跟蹤器有了反應(yīng)。

sql 是查詢了customers表。再往下執(zhí)行到第6行時,

根據(jù)外鍵customerid 去查詢orders訂單。如此。每循環(huán)一次。數(shù)據(jù)庫就會執(zhí)行2次查詢。如果有查詢結(jié)果有20條,就會有40次查詢,如果關(guān)聯(lián)的表越多。查詢的次數(shù)就會越多。
系統(tǒng)查詢能不慢嗎。
解決方法:
1 NorthwindEntities db = new NorthwindEntities(); 2 ////取消EF的延遲加載 3 db.Configuration.LazyLoadingEnabled = false; 4 ////一次性查詢出customers和Orders數(shù)據(jù),并利用ToList()放入到內(nèi)存中 5 var query = db.Customers.Include("Orders").ToList(); 6 for (int idx = 0; idx < 2; idx++) 7 { 8 var customer = query.ElementAt(idx); 9 var order = customer.Orders.FirstOrDefault();10 if (order != null)11 Console.WriteLine(order.OrderID);12 }取消EF的延遲加載。利用Include()將所需要對象一次性查詢出來。并利用ToList()將數(shù)據(jù)存入內(nèi)存中。

這是優(yōu)化后的sql運行跟蹤。我們會發(fā)現(xiàn),只實現(xiàn)了一次查詢,sql語句用了left join的方式將數(shù)據(jù)一次性查詢出來。每次循環(huán)也只會訪問內(nèi)存中。
總結(jié):
從這4行代碼中,我們發(fā)現(xiàn)
1.AsEnumerable()和 AsQueryable() 是延遲執(zhí)行,當(dāng)具體使用對象時才會執(zhí)行sql;ToList() 在使用時就已經(jīng)執(zhí)行,并數(shù)據(jù)存入內(nèi)存中。2.EF 本身默認(rèn)的是延遲加載,每個關(guān)聯(lián)的查詢,每次循環(huán)的查詢都是要執(zhí)行數(shù)據(jù)庫的。取消延遲加載,利用Include方法,可以一次性將所有數(shù)據(jù)查詢出來。以上觀點純屬個人經(jīng)驗總結(jié),歡迎各位大鳥發(fā)表看法,小菜向大家學(xué)習(xí)了。博文發(fā)表后,筆者看到許多同行的討論,也學(xué)到不少東西。筆者這里申明,自己并非黑EF。正是看到了EF的強大,才開始使用它。但是,任何東西都要學(xué)懂。就好比筆者來說,之前的用法,導(dǎo)致一個10行的列表,數(shù)據(jù)庫查詢就執(zhí)行了好幾百次。雖然這是在開發(fā)中問題不是很明顯,但是一旦正式使用,這絕對是一個隱藏的炸彈。
EF很強大,但是,不懂它心的人,只會讓自己傷心!
與廣大程序員共勉!
筆者很不平。多數(shù)同行并沒有看懂這篇博文的意思。循環(huán)2次是模擬展示列表。例如,我有表格要展示這個客戶的訂單,沒有分頁。按照前面那種方案
customer.Orders.FirstOrDefault();這個客戶有多少可訂單,數(shù)據(jù)庫執(zhí)行多少次。而第二種方案:
var query = db.Customers.Include("Orders").ToList();數(shù)據(jù)庫只執(zhí)行一次就可以。展示表格的時候都是從內(nèi)存中獲取。這就是是個明顯數(shù)據(jù)庫性能的問題。筆者虛心向大家討教!新聞熱點
疑難解答