上篇提到了效能的陷井 EntityFramework 基本效能簡介與調校,我們使用了SQL Server Profiler來檢視Entity Framework所產生出來的SQL,這篇是想提供給大家其他更簡單的方法可以檢視Linq產出的SQL,可讓我們在開發時就可以很快地測出我們所寫出來的東西會不會有潛在的效能問題
我們在開發功能時,往往免不了會去連資料庫,但寫了越多或是了解越多有關EntityFramework 的東西
就越是害怕會遇到效能的問題
當然你也可以像我前一篇一樣,使用sql server profiler來做錄資料以得到效能分析
但我個人是覺得有點麻煩,而且不是那麼方便
終於讓我在msdn的網站找到了其他更簡單的方法了Entity Framework Logging and Intercepting
至於這個使用方法有多簡單呢?
using (var db = new NorthwindEntities())
{
db.Database.Log = Console.Write;
//Your linq here
}
沒錯,就是這麼簡單,只要加上這行就可以了
但這個方法是讓你把資料輸出至console,下面會介紹其他方法在unit test或是web page中檢視效能
在驗證效能前,先來打臉一下我前一篇所寫的文章
其實這個方法1並不會產生效能問題
var expense = db.ExpenseDetail
.Select(m => new
{
user = m.Users.userName,
itemDetail = m.description,
currency = m.CurrencyMapping.CurrentDescription
}).ToList();
Console.WriteLine("method 1 takes " + sw.ElapsedMilliseconds);
我們馬上就用這個方法來看看從輸出畫面就足以把我的臉打到腫起來了
因為我們expenseDetail與User, CurrencyMapping這兩個table有建FK的關係
所以在我們還沒把expenseDetail的資料抓出來時,他還是可以繼續對FK的table做相關的操作
Entity Framework也會很聰明的幫我們產生出所需要的SQL
接下來我們就用這個方法來驗證是不是可以檢視出我們的方法有效能問題
例子我們一樣是用上一篇的sample,只是我們把seq從3改成1方便觀看
var mehtod1 = db.ExpenseDetail.Where(m => m.seq <= 1).ToList();
var result1 = mehtod1.Select(m => new
{
user = m.Users.userName,
itemDetail = m.description,
currency = m.CurrencyMapping.CurrentDescription
}).ToList();
在console的畫面中,可以看的出來的確會有效能問題,而且非常地完整可以顯示出來每個步驟花了多少時間
同樣,我們也用Include來驗證是否真的可以解決這個問題
db.Database.Log = Console.Write;
var mehtod1 = db.ExpenseDetail.Where(m => m.seq <= 1)
.Include("Users")
.Include("CurrencyMapping")
.ToList();
var result1 = mehtod1.Select(m => new
{
user = m.Users.userName,
itemDetail = m.description,
currency = m.CurrencyMapping.CurrentDescription
}).ToList();
結果一樣是沒有問題,一句SQL就可以搞定
一般來說,我們會開Unit Test來測試部份的功能,通常我也會拿Unit Test來測我的效能
非常地幸運 ,我們不用改任何寫法,直接把這段程式碼在Unit Test專案上測,只是顯示畫面不同
我們一樣可以獲得一樣的資訊
而且我覺得更棒的是,Unit Test有輸出畫面可以讓我們把結果copy 出來分析
非常方便
這是一個很好的問題,你可以參考ASP.NET MVC 4 使用 MiniProfiler 的調整方式
筆者也有使用MiniProlier 這個工具,它可以讓你知道在這個頁面上總共會產生多少個SQL
有多少個可能是duplicate的,筆者曾經用這個工具改掉了一個 LogIn時會發生的效能問題
我們可以指定 db.Database.Log = s => Log(sw, s);
讓EntityFramework在存Log的時候去執行我們客製化的function,如此一來我們就可以把結果存到執行路徑下的log Folder了
static public void Log(StreamWriter sw, string message)
{
sw.Write(message);
}
static void Main(string[] args)
{
System.Reflection.Assembly exePath = System.Reflection.Assembly.GetEntryAssembly();
string exeDir = System.IO.Path.GetDirectoryName(exePath.Location);
string logPath = string.Format(@"{0}\log", exeDir);
if (!Directory.Exists(logPath))
Directory.CreateDirectory(logPath);
using (StreamWriter sw = new StreamWriter(string.Format (@"{0}\log.txt", logPath)))
{
using (var db = new NorthwindEntities())
{
db.Database.Log = s => Log(sw, s);
var mehtod1 = db.ExpenseDetail.Where(m => m.seq <= 1).ToList();
var result1 = mehtod1.Select(m => new
{
user = m.Users.userName,
itemDetail = m.description,
currency = m.CurrencyMapping.CurrentDescription
}).ToList();
}
}
}
在不同的輸出視窗會有不同的工具可以使用,就看個人方便與習慣用什麼樣的工具
但筆者個人最喜歡使用的還是Unit Test裡使用已經包好的Service, Function
利用Mock的方式來測試網站的login 跟HttpPost的資料,以達到快速檢視結果與效能
當然在msdn的網站裡還有其他方法可以讓大家分析
參考網站
https://msdn.microsoft.com/en-US/data/dn469464
http://kevintsengtw.blogspot.tw/2013/01/aspnet-mvc-4-miniprofiler.html