EntityFramework 性能检视

上篇提到了性能的陷井 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项目上测,只是显示画面不同

我们一样可以获得一样的资讯

而且我觉得更棒的是,Unit Test有输出画面可以让我们把结果copy 出来分析

非常方便

如果我今天是在想浏览我的web page的时候检视性能怎么办?

这是一个很好的问题,你可以参考ASP.NET MVC 4 使用 MiniProfiler 的调整方式

笔者也有使用MiniProlier 这个工具,它可以让你知道在这个页面上总共会产生多少个SQL

有多少个可能是duplicate的,笔者曾经用这个工具改掉了一个 LogIn时会发生的性能问题

如何把结果写至特定folder

 我们可以指定 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