【问题标题】:How do I correctly profile Entity Framework?如何正确分析实体框架?
【发布时间】:2011-07-07 15:36:29
【问题描述】:

为了从 EF 4.1 获取单个回调,我可以编写的最少代码量是多少,该回调提供以下内容:

  • OnSQLExecuted(DbCommand cmd, DateTime start, double durationMS, string stacktrace)

目前我们使用了一种似乎会导致性能泄漏的令人讨厌的 hack,我很好奇我们如何才能在对应用程序影响最小的情况下实现此回调。


我们可以通过hacking around 将其连接到Mini Profiler - 最初我们更改了Database.DefaultConnectionFactory 但是使用默认工厂意味着您不能同时拥有两个分析工厂。所以我们走的是更激进的路线。


通常使用的技术非常简单,您可以实现:DbProviderFactoryIDbConnectionFactoryDbProviderServicesDbConnectionDbCommandDbDataReader,以便它们拦截调用和配置文件。

到目前为止,很容易......但是当您尝试连接时它会变得混乱:

   try
    {
        // ensure all the factories are loaded 
        DbProviderFactories.GetFactory("...");
    }
    catch (ArgumentException)
    {
    }

    Type type = typeof(DbProviderFactories);

    DataTable table;
    // SUPER UGLY - Can this be done in another way? 
    object setOrTable = (type.GetField("_configTable", BindingFlags.NonPublic | BindingFlags.Static) ??
                    type.GetField("_providerTable", BindingFlags.NonPublic | BindingFlags.Static)).GetValue(null);
    if (setOrTable is DataSet)
    {
        table = ((DataSet)setOrTable).Tables["DbProviderFactories"];
    }

    table = (DataTable)setOrTable;

    foreach (DataRow row in table.Rows.Cast<DataRow>().ToList())
    {
        DbProviderFactory factory;
        try
        {
            factory = DbProviderFactories.GetFactory(row);
        }
        catch (Exception)
        {
            continue;
        }

        var profType = typeof(MvcMiniProfiler.Data.EFProfiledDbProviderFactory<>).MakeGenericType(factory.GetType());


        DataRow profiled = table.NewRow();
        profiled["Name"] = row["Name"];
        profiled["Description"] = row["Description"];
        profiled["InvariantName"] = row["InvariantName"];
        profiled["AssemblyQualifiedName"] = profType.AssemblyQualifiedName;
        table.Rows.Remove(row);
        table.Rows.Add(profiled);

    }

在最新版本的 EF 上需要一些反射技巧和完全炸弹:

FileLoadException: The given assembly name or codebase was invalid. (Exception from HRESULT: 0x80131047)

FransAyende 都记录了这一点。

如何以稳健而优雅的方式连接我的分析工厂和家庭?
有没有其他方法可以得到我的回调?

【问题讨论】:

    标签: c# .net entity-framework entity-framework-4


    【解决方案1】:

    最简单的方法是使用Entity Framework tracing wrappers 并挂钩到EFTracingConnectionCommandFinished。它不会给出开始时间,但会给出持续时间(从Now 中减去,可能已经足够接近了)。

    我将代码影响称为“中等”,因为您必须更改对现有上下文类的引用。不过,这很简单。

    如果您只想跟踪而不需要实际的回调,NuGet 包有一个simple default tracing system

    编辑(添加了堆栈跟踪): EF 跟踪包装器不提供堆栈跟踪。您可以轻松获取源并添加它,但我认为这会影响性能。

    【讨论】:

    • 问题是提到EFv4.1。我不确定跟踪包装器是否适用于 DbContext API。想试了很久还是没查。
    【解决方案2】:

    虽然它是一种商业产品,但我也强烈建议您查看EF Prof。该工具由 Ayende(Oren Eini 拼写?)开发,他还制作了 NH Prof、Uber Prof (NH + EF Prof) 和 RavenDB 等产品。

    购买了他的 NH Prof,在调整 NH 时它是无价的,我希望 EF Prof 将同样有价值。

    【讨论】:

    • 我们已经有一个开源的半工作解决方案,code.google.com/p/mvc-mini-profiler/source/browse/… 问题是它会泄漏性能并首先使用 EF 代码。我很确定 Ayende 也有同样的问题。请参阅我对斯蒂芬斯答案的评论以获取完整的上下文。
    • @Sam Saffron 我看了你的回答,但我似乎没有看到任何与 EF Prof. 相关的内容。它很可能有类似的问题,但也许你应该尝试 EF Prof 和找出?还是直接与 Ayende 交谈?他肯定会通过他的博客和谷歌群组回答用户的问题。
    • EFProf 推荐上面有 2 -1 票,而 EFProf 推荐这里有 7 +1 票。我觉得我正在服用疯狂的药丸!
    • @MikeCole 我认为它对重复我的答案投了反对票
    • @ChrisMarisic,啊,可能,我错过了时间戳。
    【解决方案3】:

    首先:如果您正在寻找可以直接在 EF 中触发您自己的事件的自定义实现,请忽略它。 ADO.NET 团队不知何故忘记了实现任何扩展点,他们甚至忘记了实现任何日志记录(除了将 ObjectQuery / DbQuery 转换为 SQL,但它不处理延迟加载或数据修改)。

    我相信与 EF 一起使用的每个跟踪实现都是通过创建自定义 DbProviderFactory 来完成的,它包装了真实的工厂并包装了真实的 ConnectionCommand 等。在提到的跟踪包装器中对此进行了非常清楚的描述。

    有些商业工具已经可以满足你的需求了

    • 提到 EF Prof 是很棒的工具,但每个座位的成本为 300 美元。
    • 替代方案是Huagati Query Profiler。尤其是this screen shot 看起来像您正在寻找的东西。价格要低得多(每个席位 40 美元),并且支持 Linq-to-sql、Entity Framework 和 LLBLGen。

    这两种工具都有免费试用版,因此您可以下载并试用它们。

    顺便说一句。如果您有 VS 2010 Ultimate,也许您可​​以从 Intelli Trace 获得很多您正在寻找的信息。您可以在 MSDN Magazine 中了解所有当前可用的替代方案。

    我认为有一个很大的问号——您使用的是 DbContext 还是 ObjectContext(您提到了 EFv4.1)?提到的工具和跟踪包装器是为 ObjectContext API 创建的,所以我不确定它们如何与 DbContext API 一起使用。您仍然可以从DbContext 获得ObjectContext,但如果该工具期望EntityConnection 而不是普通连接,这将是一个问题。

    【讨论】:

    • 我希望它可以与 dbcontext 一起使用 ...这项工作适用于 mvc mini profiler,请参阅 cmets on Stephens answer ...
    • 就像说使用 EF 6 你现在有拦截点,你可以添加计时器和记录器。看看 IDbCommandInterceptor。我检测到“长时间运行”的查询并记录完整的 Sql 并发出警告,以便可以从日志中获取它们。
    【解决方案4】:

    我可以推荐 Entity Framework Profiler 和每月订阅适合您的需要,每月最低费用为 16 美元。我们在使用 DbContext 时遇到了一些性能问题,它提供了很好的视觉信息来解决这些问题。您可以将 EF Profiler 与您的持续集成服务器集成并不断提高您的性能。

    http://efprof.com/

    【讨论】:

    • 我不是在寻找分析器,我在寻找分析器可以使用的技术。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-24
    相关资源
    最近更新 更多