Как правильно профилировать Entity Framework?
Каков минимальный объем кода, который я могу написать, чтобы получить один обратный вызов из EF 4.1, который обеспечивает следующее:
-
OnSQLExecuted(DbCommand cmd, DateTime start, double durationMS, string stacktrace)
В настоящий момент мы используем неприятный хак, который, кажется, просачивается, мне интересно, как мы можем достичь этого обратного вызова с минимальным воздействием на приложение.
Мы можем подключить это в Mini Profiler от взломать - в основном мы изменили Database.DefaultConnectionFactory
, однако сбрасывание по умолчанию factory означает, что у вас не может быть двух профилирующих заводов, идущих одновременно. Таким образом, мы пошли более агрессивным путем.
Используемая техника довольно проста, вы реализуете: DbProviderFactory
, IDbConnectionFactory
, DbProviderServices
, DbConnection
, DbCommand
и DbDataReader
таким образом, чтобы они перехватывали вызовы и профиль.
До сих пор, просто... однако это становится беспорядочным, когда вы пытаетесь подключить это:
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)
Это было документировано как Frans и Ayende.
Как подключить мои профилирующие фабрики и семью прочным и элегантным способом?
Есть ли другой способ получить мой обратный вызов?
Ответы
Ответ 1
Самый простой способ - использовать Обертки трассировки Entity Framework и подключиться к EFTracingConnection
CommandFinished
. Это не дает вам время начала, но оно дает вам продолжительность (которая вычитается из Now
, вероятно, достаточно близка).
Я бы назвал эффект кода "умеренным", так как вам нужно изменить ссылки на существующий класс контекста. Это довольно просто, хотя.
Если вы просто хотите отслеживать и не нуждаетесь в фактическом обратном вызове, пакет NuGet имеет простую систему отслеживания по умолчанию.
Изменить (добавлена трассировка стека): Обертки трассировки EF не дают вам трассировки стека. Вы можете получить источник и добавить его без особых трудностей, но я думаю, что это повлияет на производительность.
Ответ 2
В то время как это коммерческий продукт, я также настоятельно рекомендую посмотреть EF Prof. Этот инструмент был разработан Айенде (Oren Eini spelling?), Который также сделал NH Prof, Uber Prof (NH + EF Prof) и RavenDB среди других продуктов.
Купив его NH Prof, при настройке NH это было бесценно, и я ожидал бы, что EF Prof будет таким же ценным, соответственно.
Ответ 3
Во-первых: Если вы ищете пользовательскую реализацию, в которой вы можете инициировать собственное событие непосредственно в EF, забудьте об этом. Команда ADO.NET каким-то образом забыла внедрить любые точки расширения и даже забыла реализовать любое ведение журнала (за исключением преобразования ObjectQuery
/DbQuery
в SQL, но оно не обрабатывает ленивую загрузку или модификации данных).
Я считаю, что каждая реализация трассировки, используемая с EF, выполняется путем создания пользовательского DbProviderFactory
, который обертывает реальный factory и обертывает реальные Connection
, Command
и т.д. Это очень четко описано в упомянутых обертки трассировки.
Есть коммерческие инструменты, которые уже делают то, что вы хотите
- Упомянутый EF Prof - отличный инструмент, но он стоит 300 долларов за место.
- Альтернатива Профайлер запросов Huagati. Особенно этот скриншот выглядит так, как вы ищите. Цена намного ниже ($ 40 за место), и она поддерживает Linq-to-sql, Entity Framework и LLBLGen.
Оба инструмента имеют бесплатную пробную версию, поэтому вы можете их скачать и попробовать.
Btw. возможно, вы можете получить много информации, которую ищете от Intelli Trace, если у вас есть VS 2010 Ultimate. Вы можете прочитать обо всех доступных в настоящее время альтернативах в MSDN Magazine.
Я думаю, что есть один большой вопросительный знак - вы используете DbContext или ObjectContext (вы упомянули EFv4.1)? Упомянутые инструменты и трассировочные обертки были созданы для ObjectContext API, поэтому я не уверен, как они работают с DbContext API. Вы все равно можете получить ObjectContext
от DbContext
, но если инструмент ожидает EntityConnection
вместо обычного соединения, это будет проблемой.
Ответ 4
Я могу порекомендовать Entity Framework Profiler и ежемесячную подписку, подходящую для вас, с минимальными затратами $16 US в месяц. У нас были проблемы с производительностью с DbContext, и это обеспечило хорошую визуальную информацию, чтобы исправить это. вы можете интегрировать профилировщик EF с сервером непрерывной интеграции и улучшать свою производительность.
http://efprof.com/