mvc-mini-profiler замедляет Entity Framework - PullRequest
12 голосов
/ 23 июня 2011

Я настроил 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 сделать, что это неправильно? Я все еще передаю неверные данные?

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

Ответы [ 2 ]

5 голосов
/ 25 июля 2011

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

см .: 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 });

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

0 голосов
/ 27 июня 2011

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

...