Подтвердить что ты не робот

Mvc-mini-profiler замедляет работу Entity Framework

Я установил 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 неправильно? Я все еще кормлю его неправильными данными?

Я думаю, что это та самая проблема, с которой столкнулся этот человек.

4b9b3361

Ответ 1

Я только что решил эту проблему сегодня.

см. http://code.google.com/p/mvc-mini-profiler/issues/detail?id=43

Случилось так, что некоторые из наших причудливых хаков недостаточно хорошо кэшировались. В частности:

var workspace = new System.Data.Metadata.Edm.MetadataWorkspace(
     new string[] { "res://*/" },       
     new Assembly[] { typeof(T).Assembly });

Это очень дорогостоящий вызов, поэтому нам нужно кэшировать рабочее пространство.

Ответ 2

Профилирование, по определению, будет влиять на производительность профилируемого приложения. Профилировщик должен вставлять собственные вызовы методов во всем приложении, перехватывать системные вызовы низкого уровня и записывать все эти данные где-то (что означает запись на диск). Все эти задачи занимают ценные циклы процессоров, память и доступ к диску.