Java, Groovy on Grails, PHP, Kohana

Блог о программировании на Java, Groovy on Grails, PHP, kohana

Оптимизация запросов к базе данных Kohana 3.2 (ORM & JOIN)

В kohana есть замечательный модуль ORM, он значительно облегчает жизнь разработчикам.
Хотя как известно “бесплатный сыр бывает только в мышеловке”.

Используя ORM мы получаем простой и удобный доступ к базе данных, как к обычному объекту, но при этом в конечном итоге kohana все же создает обычные SQL запросы.

Таблица пользователей ‘users’
id role_id name
1 2 Вася
2 3 Петя
3 1 Степа
Таблица ролей пользователей ‘roles’
id role_name
1 root
2 admin
3 manager

Допустим мы создали 2 модели к вышеописанным таблицам:

  • user.php
  • role.php

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

$users = ORM::factory('users')->find_all();
foreach($users as $user)
{
echo 'имя = ' . $user->name . ' роль ='. $user->roles->role_name . '<br />';
}

При этом у нас будут созданы kohanой следующие запросы к БД:

  1. SELECT * FROM users
  2. SELECT * FROM roles WHERE id=X, в количестве 3 шт., где X подставляется значение role_id текущей записи из таблицы users

Суть проблемы сводится к следующему: имея, к примеру, 1000 пользователей и выводя их данные на страницу мы получаем 1000+1 запрос к БД, что само по себе есть – плохо, скорость вывода данных катастрофически падает. А если у таблицы с пользователями есть еще 10 связанных таблиц?!
Использование ORM в таком виде оправдано для вывода данных одного пользователя, но для вывода данных многих пользователей его применять нельзя.
Как вариант, можно использовать join в ORM, например:

$users = ORM::factory('users')
->join('roles', 'RIGHT OUTER')
->on('user.role_id', '=', 'roles.id')
->select('roles.*')
->find_all();
foreach($users as $user)
{
echo 'имя = ' . $user->name . ' роль ='. $user->role_name . '<br />';
}

В этом случае у нас будет один запрос, который получит из БД все необходимые данные:
SELECT `users`.*, `roles`.*
FROM `users` AS `user`
RIGHT OUTER JOIN `roles` ON (`user`.`role_id` = `roles`.`id`)

P.S. kohana изучаю недавно, все писал из памяти. Буду рад комментариям и замечаниям.

  • Recent Posts