Doctrine 2 EntityManager вызывает потерю времени при первом запросе

Недавно я интегрировал Doctrine 2 ORM в CodeIgniter 2. Я настроил Doctrine 2 как библиотеку и автоматически загрузил ее в CodeIgniter. На странице я создаю экземпляр диспетчера сущностей доктрины следующим образом:

private static $em = null;

public function __construct() {
    parent::__construct();
    $this->em = $this->doctrine->em;
}

И тогда я начинаю использовать Entity Manager, когда это необходимо. У меня проблема в том, что при каждом запросе страницы Entity Manager инициализируется некоторое время (примерно 1 секунда). Это заставляет пользователя ждать, пока страница загрузится. Ниже вы можете увидеть некоторые результаты производительности, которые я измерил:

BENCHMARKS  
Loading Time: Base Classes          0.0166
Doctrine                            0.0486
GetArticle                          1.0441
Functions                           0.0068
Controller Execution Time           1.1770
Total Execution Time                1.1938

Функция GetArticle в основном выполняет вызов EntityManager->find():

$currentart = $this->em->find('Entities\Article', $artid);

Мне приходится ждать эту 1 секунду, даже если я использую метод EntityManager->createQuery().

На каждой странице у меня есть потеря времени примерно на 1 секунду из-за первого запроса EntityManager.

Это распространено?

Эта 1 секунда связана с тем, что EntityManager необходимо установить соединение с БД? Однако функции/запросы после первого запроса выполняются довольно быстро.


person hdz200    schedule 23.07.2011    source источник


Ответы (1)


Самая трудоемкая вещь, которую делает Doctrine, — это загрузка метаданных для ваших сущностей, будь то аннотации, XML или YAML. Doctrine лениво загружает метаданные, когда это возможно, поэтому вы не заметите падения производительности, пока не начнете использовать сущности. Поскольку метаданные не изменяются, если вы не вносите изменения в свой код, Doctrine позволяет кэшировать метаданные между запросами. Запросы DQL также необходимо преобразовывать в SQL, поэтому Doctrine предоставляет для этого другую конфигурацию кэширования.

В производственной среде вы должны настроить эти кеши (похоже, вы уже это сделали, но для других, читающих это):

$cache = new \Doctrine\Common\Cache\ApcCache(); // or MemcacheCache $configuration->setMetadataCachImpl($cache); // caches metadata for entities $configuration->setQueryCachImpl($cache); // caches SQL from DQL queries

Чтобы предотвратить полную загрузку метаданных при загрузке первой страницы, вы можете настроить подогреватель кеша, который загружает все метаданные класса и сохраняет их в кеше.

$em->getMetadataFactory()->getAllMetadata();

Еще одним потенциальным узким местом является создание прокси-классов. Если это неправильно настроено в производственной среде, Doctrine будет генерировать классы и сохранять их в файловой системе при каждой загрузке страницы. Эти прокси-классы не изменяются, пока не изменится код сущности, поэтому в этом опять же нет необходимости. Чтобы ускорить процесс, вы должны сгенерировать прокси с помощью инструмента командной строки (orm:generate-proxy) и отключить автогенерацию:

$configuration->setAutoGenerateProxyClasses(false);

Надеюсь, это поможет вам. Дополнительную информацию можно найти по адресу http://www.doctrine-project.org/docs/orm/2.0/en/reference/improving-performance.html#bytecode-cache

person Michael Ridgway    schedule 25.07.2011
comment
Привет, спасибо за ваш ответ. К сожалению, я уже прочитал материал по ссылке, которую вы прислали. И, как вы указали, я уже использую ApcCache. Похоже, что он загружает метаданные в каждом запросе, даже когда я использую ApcCache. Еще одна интересная вещь, на которую стоит обратить внимание, это то, что я не вижу никакой разницы в производительности между ApcCache и ArrayCache. Из статей, которые я прочитал до сих пор, я ожидаю, что мое приложение должно работать лучше, когда я использую ApcCache. Может быть, мой ApcCache настроен неправильно? Или, может быть, потому что я разрабатываю свое приложение на локальном хосте? - person hdz200; 25.07.2011
comment
Где я должен поместить следующий код: $em->getMetadataFactory()->getAllMetadata(); Я также заранее сгенерировал классы Proxy с помощью orm:generate-proxy. Так что проблема должна быть где-то в другом. - person hdz200; 25.07.2011
comment
ApcCache требует, чтобы у вас был установлен APC и чтобы он правильно работал с PHP. Проверьте свой phpinfo(), чтобы убедиться, что он действительно работает. - person Michael Ridgway; 26.07.2011
comment
APC уже установлен и включен в PHP... Все равно спасибо :) - person hdz200; 26.07.2011
comment
Хорошо, я не могу думать ни о чем другом, кроме, возможно, что-то с вашей картой. Можете ли вы опубликовать свою сущность + сопоставление? - person Michael Ridgway; 26.07.2011
comment
Я думаю, это было потому, что я работал на местном уровне. Я попробовал это на сервере, и там я не сталкиваюсь с проблемами w.r.t. скорость. Я также применил метод getAllMetadata(), который вы посоветовали. Спасибо за помощь! - person hdz200; 27.07.2011