28
В предыдущей статье (Создаем модели правильно – Часть 1) я рассматривал необходимость ограничений целостности для базы данных. Сегодня я бы хотел рассмотреть, как оптимизировать запросы, создаваемые CakePHP.

В своем тестовом приложении на локальном компьютере я реализую структуру базы данных, разработанную нами в предыдущей части этой статьи, а также накладываю ограничения целостности:
alter table `comments` add constraint `key_1` foreign key comments(`article_id`) references articles(`id`) on update cascade on delete cascade
Если Вы экспортировали созданную структуру сразу из MySQL WorkBench, то в этом нет необходимости – ограничения будут созданы автоматически.
Для чистоты эксперимента я добавляю в таблицу Статей 5000 записей, сгенерированных случайным образом. На листинге приведен пример модели, которая служит для соединения с таблице Articles:
<?php
class Article extends AppModel {
var $name = 'Article';
var $displayField = 'title';
var $hasMany = array(
'Comment' => array(
'className' => 'Comment',
'foreignKey' => 'article_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
}
?>
Структура простая, и именно в таком виде она чаще всего и используется.
Кроме Статей в базу данных я добавляю Комментарии, по 5 на каждую статью. Итого, в базе хранится 30000 записей, что уже, согласитесь, немало.
Результаты выборки нас сейчас особенно не интересуют, только время выполнения запросов, поэтому в качестве отображения будем использовать простую конструкцию:
<pre> <?php print_r($articles); ?> </pre>
Будем рассматривать по очереди, что можно сделать с моделью.
1. Простая выборка данных
function find1() {
$articles = $this->Article->find(
'all'
);
$this->set(
'articles',
$articles
);
}
Выглядит она банально и просто, время выполнения такого запроса максимально и я даже не дождался, когда же наконец он выполнится.
Пути оптимизации:
Реализовать эти два пути можно как на уровне отдельного запроса, так и на уровне модели в целом. Если мы хотим выбрать определенное количество записей только в этот раз, тогда запрос нужно оптимизировать следующим образом:
$articles = $this->Article->find( 'all', array( 'limit' => '20' ) );
Время выполнения запроса составляет 124 микросекунды.

Так мы выберем только 20 записей. Часто именно по 20 записей за раз и нужно, например, на страницу.
Если ассоциаций много, то выполнение занимает еще большее время, но как это часто бывает, не все ассоциации нужны на одной странице, поэтому для повышения скорости выполнения запроса можно отключать ненужные ассоциации. Выглядит это следующим образом:
$this->Article->unbindModel( array ( 'hasMany' => array ( 'Comment' ) ) );
Если перед вызовом написать представленный выше код, то время выполнения запроса значительно сокращается:

2. Запросы, хранимые прямо в модели
Рассмотрим еще способ, как мы можем сократить время, необходимое на выборку данных, в том числе на написание кода для его многократного использования. Так как MySQL не особенно хорошо дружит с таким объектом базы данных, как представление, то его можно реализовать средствами CakePHP. Для этого прямо в модели создадим функцию следующего вида:
function getLast() {
return $this->find(
'all',
array (
'limit' => '20',
'conditions' => array (
'created > (curdate() - interval 7 day)'
)
)
);
}
Теперь в контроллере мы можем вызвать эту функцию:
$articles = $this->Article->getLast();
Использование такого подхода позволяет сократить количество кода, которое необходимо написать, а также повторное его использование.
3. Кэширование результатов запросов.
Есть запросы, которые пользователи выполняют постоянно, например, выборка данных для автоподстановки в какое-либо поле. Чтобы каждый раз не гонять этот запрос в базу данных, его результаты можно закешировать и отдавать уже готовые данные без необходимости их заново извлекать. Чтобы включить кеширование результатов запросов, необходимо в модель дописать следующую строку:
var $cacheQueries = true;
На сегодня это все, расслабляемся и смотрим видеоролик про мальчугана, который просто нереально играет на гитаре:
Joomla Linux Тайм-менеджмент CakePHP PHP&MySQL PhotoSight Аниме Хостинг Проектирование ИС Интервью GTD
кроме анбинда модели существуют еще опция запроса и свойство модели recursive
Согласен, unbind – неудобно и долго, но иногда без него не обойтись.