zoukankan      html  css  js  c++  java
  • 使用工具追踪Entity Framework生成的SQL

    学习entity framework期间收集的文章,转自http://www.cnblogs.com/hiteddy/archive/2011/10/01/Difference_among_IQueryable_IEnumeralb_IList_in_Entity_Framework.html

    使用Entity Framework等ORM框架的时候,SQL对于使用者来说是透明的,往往很多人也不关心ORM所生成的SQL,然而系统出现性能问题的时候就必须关注生成的SQL以发现问题所在。

    使用过Toplink的朋友知道很只要设置日志打印级别=FINE就可以配置使之生成的SQL在服务器中打印出来,Entiry Framework没有那么幸运,在以前要检测生成SQL的唯一方法是SQL Server Profiler,但使用起来并不方便,结果也不能自动保存到文件中。

    Tracing and Caching Provider Wrappers for Entity Framework是Entity Framework Team新推出的开源SQL追踪和二级缓存的解决方案。原理是在负责执行具体SQL语句的data provider(SqlClient或者其他Client)之上插入了一层WrappingProvider,用于监控DbCommand.ExecuteReader(), ExecuteScalar() and ExecuteNonQuery(),将Sql命令输出到指定介质或者将查询结果缓存起来以重用。

    使用方法很简单,下载源代码编译后将dll添加到项目中,新加一个类WrappedNorthWindEntities继承原有的Entities即可,详见源代码中的示例。

    测试IQueryable, IEnumerable, IList的区别

    下面我们使用EF Wrapper来监测Entify Framework中IQueryable, IEnumerable和IList所生成的SQL。

    TestIQueryable

    private static void TestIQueryable()
    {
    using (var ctx = new WrappedNorthWindEntities())
    {
    IQueryable<Product> expression = ctx.Products.Take(5);
    IQueryable<Product> products = expression.Take(2); // A 不执行SQL
    Console.WriteLine(products.Count());          // B SELECT COUNT(1) FROM ( SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products] ))
    Console.WriteLine(products.Count());          // C SELECT COUNT(1) FROM ( SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products] ))
    foreach (Product p in products)             // D SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products]
    {
    Console.WriteLine(p.ProductName);
    }
    foreach (Product p in products)             // E SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products] )
    {
    Console.WriteLine(p.ProductName);
    }
    }
    }

    TestIEnumerable

    private static void TestIEnumerable()
    {
    using (var ctx = new WrappedNorthWindEntities())
    {
    IEnumerable<Product> expression = ctx.Products.Take(5).AsEnumerable();
    IEnumerable<Product> products = expression.Take(2); // A 不执行SQL
    Console.WriteLine(products.Count());          // B SELECT TOP (5) * FROM [dbo].[Products]
    Console.WriteLine(products.Count());          // C SELECT TOP (5) * FROM [dbo].[Products]
    foreach (Product p in products)             // D SELECT TOP (5) * FROM [dbo].[Products]
    {
    Console.WriteLine(p.ProductName);
    }
    foreach (Product p in products)             // E SELECT TOP (5) * FROM [dbo].[Products]
    {
    Console.WriteLine(p.ProductName);
    }
    }
    }


    复制代码
    private static void TestIEnumerable()
    {
    using (var ctx = new WrappedNorthWindEntities())
    {
    IEnumerable<Product> expression = ctx.Products.Take(5).AsEnumerable();
    IEnumerable<Product> products = expression.Take(2); // A 不执行SQL
    Console.WriteLine(products.Count());          // B SELECT TOP (5) * FROM [dbo].[Products]
    Console.WriteLine(products.Count());          // C SELECT TOP (5) * FROM [dbo].[Products]
    foreach (Product p in products)             // D SELECT TOP (5) * FROM [dbo].[Products]
    {
    Console.WriteLine(p.ProductName);
    }
    foreach (Product p in products)             // E SELECT TOP (5) * FROM [dbo].[Products]
    {
    Console.WriteLine(p.ProductName);
    }
    }
    }
    复制代码

    TestIList

    private static void TestIList()
    {
    using (var ctx = new WrappedNorthWindEntities())
    {
    var expression = ctx.Products.Take(5);
    IList<Product> products = expression.Take(2).ToList(); // A SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products]

    Console.WriteLine(products.Count());           // B 不执行SQL
    Console.WriteLine(products.Count());           // C 不执行SQL
    foreach (Product p in products)              // D 不执行SQL
    {
    Console.WriteLine(p.ProductName);
    }
    foreach (Product p in products)             // E 不执行SQL
    {
    Console.WriteLine(p.ProductName);
    }
    }
    }


    复制代码
    private static void TestIList()
    {
    using (var ctx = new WrappedNorthWindEntities())
    {
    var expression = ctx.Products.Take(5);
    IList<Product> products = expression.Take(2).ToList(); // A SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products]

    Console.WriteLine(products.Count());           // B 不执行SQL
    Console.WriteLine(products.Count());           // C 不执行SQL
    foreach (Product p in products)              // D 不执行SQL
    {
    Console.WriteLine(p.ProductName);
    }
    foreach (Product p in products)             // E 不执行SQL
    {
    Console.WriteLine(p.ProductName);
    }
    }
    }
    复制代码

    测试结果

    1. IQueryable和IEnumerable都是延时执行(Deferred Execution)的,而IList是即时执行(Eager Execution)
    2. IQueryable和IEnumerable在每次执行时都必须连接数据库读取,而IList读取一次后,以后各次都不需连接数据库。前两者很容易造成重复读取,性能低下,并且可能引发数据不一致性
    3. IQueryable和IEnumerable的区别:IEnumberalb使用的是LINQ to Object方式,它会将AsEnumerable()时对应的所有记录都先加载到内存,然后在此基础上再执行后来的Query。所以上述TestIEnumerable例子中执行的SQL是"select top(5) ...",然后在内存中选择前两条记录返回。

    以下是一个IQueryable引发数据不一致性的例子:记录总数和记录详情两者本应一致,但由于IQueryable前后两次读取数据库,结果是现实有10条记录,却输出11条详情。

    IQueryable Data Inconsistancy

    IQueryable<Product> products = ctx.Products.All();
    //开始的时候数据库product表中有10条记录, count = 10
    int count = products.Count();
    Console.WriteLine("Count of products:"+count);

    //此时另一进程添加一个产品进数据库
    //会重新读取数据库并输出11个产品名称
    foreach (Product p in products)
    {
    Console.WriteLine(p.ProductName);
    }


    复制代码
        IQueryable<Product> products = ctx.Products.All();
    //开始的时候数据库product表中有10条记录, count = 10
    int count = products.Count();
    Console.WriteLine("Count of products:"+count);
            
    //此时另一进程添加一个产品进数据库
        //会重新读取数据库并输出11个产品名称
    foreach (Product p in products)
    {
    Console.WriteLine(p.ProductName);
    }
    复制代码

    结论

    基于性能和数据一致性这两点,我们使用IQueryable时必须谨慎,而在大多数情况下我们应使用IList。

    • 当你打算马上使用查询后的结果(比如循环作逻辑处理或者填充到一个table/grid中),并且你不介意该查询会即时执行,使用ToList()
    • 当你希望查询后的结果可以供调用者(Consummer)作后续查询(比如这是一个"GetAll"的方法),或者你希望该查询延时执行,使用AsQueryable()
  • 相关阅读:
    SqlServer 查看数据库中所有存储过程
    SqlServer 查看数据库中所有视图
    SqlServer 查询表的详细信息
    SqlServer 遍历修改字段长度
    net core 操作Redis
    Tuning SharePoint Workflow Engine
    Open With Explorer
    Download language packs for SharePoint 2013
    Change Maximum Size For SharePoint List Template when Saving
    Six ways to store settings in SharePoint
  • 原文地址:https://www.cnblogs.com/colder/p/4192726.html
Copyright © 2011-2022 走看看