Использование `contains` замедляет вызов find () в CakePHP 3, в то время как сам запрос по-прежнему быстрый - PullRequest
0 голосов
/ 11 июня 2018

У меня есть вызов CakePHP 3 find(), который Я некоторое время пытался оптимизировать .Я сузил его до этих двух фрагментов, с той лишь разницей, что удален параметр contain.Время измерялось с помощью DebugKit .

Включая contain:

public function qrytest() {
    $table = TableRegistry::get('OrderOptions', array(
        'className' => 'App\Model\Table\Opencart\OrderOptionsTable',
    ));
    $results = $table->find('all', array(
        'fields' => array(
            'OrderOptions.order_product_id',
            'OrderOptions.order_option_id',
            'OrderOptions.value',
        ),
        'conditions' => array(
            'OrderOptions.order_id' => 123,
        ),
        'contain' => array(
            'OpencartProductOptions' => array(
                'OpencartOption',
            ),
            'OpencartOrderProducts' => array(
                'OpencartOrders' => array(
                    'OpencartShippingZone',
                ),
                'OpencartProduct' => array(
                    'OpencartWeightClass',
                ),
            ),
            'OpencartProductOptionValues',
        ),
    ))->all();
    $this->viewBuilder()->template('anEmptyView');
}

Sql Log : 1/99 мс; Таймер : 4,42 с / 5,72 МБ


Нет contain

public function qrytest() {
    $table = TableRegistry::get('OrderOptions', array(
        'className' => 'App\Model\Table\Opencart\OrderOptionsTable',
    ));
    $results = $table->find('all', array(
        'fields' => array(
            'OrderOptions.order_product_id',
            'OrderOptions.order_option_id',
            'OrderOptions.value',
        ),
        'conditions' => array(
            'OrderOptions.order_id' => 123,
        ),
        // contain parameter removed; nothing else changed
    ))->all();
    $this->viewBuilder()->template('anEmptyView');
}

Sql Log : 1/92 мс; Таймер : 1,06 с / 4,83 МБ


Сводка : включение параметра содержит заставляет контроллер визуализироваться почти 5 секунд, не изменяя фактический запросвремя значительно.Расширение вкладки Таймеров DebugKit показывает Действие контроллера: 4 388,74 мс (снимки экрана часть 1 , часть 2 )


Первое, что приходит на ум, это оптимизация объединений и индексов, но если вы посмотрите на результаты выше, сам запрос, по-видимому, занимает одинаковое количество времени в обоих случаях.Для подтверждения я выполнил исходный запрос (включая JOIN) непосредственно в MySQL Workbench , и это занимает около 100 мс, что соответствует тому, что я вижу в выводе DebugKit.Кроме того, я действительно все-таки создал все необходимые индексы некоторое время назад.

Тем не менее, я начинаю думать, что проблема не в моем запросе MySQL, а в том, как CakePHP его обрабатывает, и здесь мне нужна помощь.

Я могуопубликовать информацию о структуре таблицы, если вам нужно.

Обновления

  • Нет разницы между включенной и выключенной гидратацией.Попробовал $query->enableHydration(false); и $query->hydrate(false); (согласно query-builder.html # receive-arrays-вместо-entity-* )
  • Отключил отладку, явно указав 'debug' => false, по-прежнемумедленно: время = 4.30 с, измеренное браузером
  • Вот сгенерированный запрос:

    SELECT 
      `OrderOptions`.`order_product_id` AS `OrderOptions__order_product_id`, 
      `OrderOptions`.`order_option_id` AS `OrderOptions__order_option_id`, 
      `OrderOptions`.`value` AS `OrderOptions__value` 
    FROM 
      `order_option` `OrderOptions` 
      LEFT JOIN `product_option` `OpencartProductOptions` ON `OpencartProductOptions`.`product_option_id` = (
        `OrderOptions`.`product_option_id`
      ) 
      LEFT JOIN `option` `OpencartOption` ON `OpencartOption`.`option_id` = (
        `OpencartProductOptions`.`option_id`
      ) 
      LEFT JOIN `order_product` `OpencartOrderProducts` ON `OpencartOrderProducts`.`order_product_id` = (
        `OrderOptions`.`order_product_id`
      ) 
      LEFT JOIN `order` `OpencartOrders` ON `OpencartOrders`.`order_id` = (
        `OpencartOrderProducts`.`order_id`
      ) 
      LEFT JOIN `zone` `OpencartShippingZone` ON `OpencartShippingZone`.`zone_id` = (
        `OpencartOrders`.`shipping_zone_id`
      ) 
      LEFT JOIN `product` `OpencartProduct` ON `OpencartProduct`.`product_id` = (
        `OpencartOrderProducts`.`product_id`
      ) 
      LEFT JOIN `weight_class` `OpencartWeightClass` ON `OpencartProduct`.`weight_class_id` = (
        `OpencartWeightClass`.`weight_class_id`
      ) 
      LEFT JOIN `product_option_value` `OpencartProductOptionValues` ON `OpencartProductOptionValues`.`product_option_value_id` = (
        `OrderOptions`.`product_option_value_id`
      ) 
    WHERE 
      `OrderOptions`.`order_id` = 123
    
  • Вот вывод XDebug:

    XDebug Output

1 Ответ

0 голосов
/ 21 июня 2018

Я работаю с крупными корпоративными проектами, и внешним интерфейсом является CakePHP, но когда вы начинаете обсуждение производительности в рамках среды для быстрого развития, вы предъявляете требование, что этот тип инфраструктуры не обрабатывает сам по себе.

Используйте CakePHP, когда это уместно, например, для отображения реестров из таблицы.

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

Используя EXPLAIN, вы можете установить соответствующий INDEX для QUERY, когда это достаточно оптимизировано, настройте представление просто, например:

CREATE VIEW %VIEW-NAME% AS %QUERY%

Если использование представлений недостаточноНапример, если представления по-прежнему имеют большие наборы данных, начните работать с STORED PROCEDURES, это отличный способ работы, потому что вы можете запустить часть своей программы внутри базы данных, и снова вы используете CakePHP только для отображения этих данных.

...