Я настроил mvc-mini-profiler для своего сайта MVC 3 на платформе Entity Framework. Все правильно настроено; Начиная профилирование в Application_Start, заканчивая его в Application_End и так далее. Часть профилирования работает просто отлично.
Однако, когда я пытаюсь переключить генерацию объектов модели данных на профилируемые версии, производительность падает до предела. Не каждый SQL-запрос, но некоторые запросы занимают примерно 5-кратную загрузку всей страницы. (Самая первая загрузка страницы после запуска IIS Express занимает немного больше времени, но это поддерживается.)
Незначительное время (около 2 мс) тратится на запросы, выполнение и «чтение данных» SQL, в то время как эта строка:
var person = dataContext.People.FirstOrDefault(p => p.PersonID == id);
... при включении в using(profiler.Step())
записывается как занимающее 300-400 мс. Я провел профилирование с помощью dotTrace, который подтвердил, что время в EF обычно тратится как обычно (профилируемые компоненты появляются очень быстро), только это занимает гораздо больше времени.
Это наводит меня на мысль, что в соединении или некоторых его составных частях отсутствуют достаточные данные, из-за чего EF работает намного хуже.
Это то, что я использую для создания объекта контекста (класс моей модели edmx называется DataContext):
var conn = ProfiledDbConnection.Get(
/* returns an SqlConnection */CreateConnection());
return CreateObjectContext<DataContext>(conn);
Первоначально я использовал предоставленный mvc-mini-profiler метод ObjectContextUtils.CreateObjectContext
. Я углубился в это и заметил, что он установил строку пути рабочей области метаданных подстановочного знака. Поскольку слой базы данных выделен для одного проекта и нескольких сайтов MVC, как и другие проекты, использующие код, эти пути изменились, и я бы предпочел быть более конкретным. Кроме того, я думал, что это было причиной проблемы с производительностью. Я продублировал функциональность CreateObjectContext
в своем собственном проекте, чтобы обеспечить это следующим образом:
public static T CreateObjectContext<T>(DbConnection connection) where T : System.Data.Objects.ObjectContext {
var workspace = new System.Data.Metadata.Edm.MetadataWorkspace(
GetMetadataPathsString().Split('|'),
// ^-- returns
// "res://*/Redacted.csdl|res://*/Redacted.ssdl|res://*/Redacted.msl"
new Assembly[] { typeof(T).Assembly });
// The remainder of the method is copied straight from the original,
// and I carried over a duplicate CtorCache too to make this work.
var factory = DbProviderServices.GetProviderFactory(connection);
var itemCollection = workspace.GetItemCollection(System.Data.Metadata.Edm.DataSpace.SSpace);
itemCollection.GetType().GetField("_providerFactory", // <==== big fat ugly hack
BindingFlags.NonPublic | BindingFlags.Instance).SetValue(itemCollection, factory);
var ec = new System.Data.EntityClient.EntityConnection(workspace, connection);
return CtorCache<T, System.Data.EntityClient.EntityConnection>.Ctor(ec);
}
... но это, похоже, не имеет большого значения. Проблема все еще существует, использую ли я вышеупомянутую взломанную версию, которая более специфична для путей рабочей области метаданных, или версию, предоставленную mvc-mini-profiler. Я просто подумал, что упомяну, что тоже пробовал.
Исчерпав все это, я нахожусь в тупике. Еще раз: когда я просто предоставляю свой контекст данных как обычно, производительность не теряется. Когда я предоставляю «профилируемый» контекст данных, производительность для определенных запросов падает (я тоже не знаю, что на это влияет). Что может mvc-mini-profiler сделать, что это неправильно? Я все еще передаю неверные данные?
Я думаю, что это та же проблема, с которой столкнулся этот человек .