Когда Kohana ORM может навредить или преимущество группирующих запросов SQL

Итак, после долгого перерыва я снова готов написать статью. Перерыв был по весьма уважительной причине — делал свой первый относительно крупный проект на Kohana Framework. И естественно, для базы данных я использовал ORM. Эта статья — о ловушках, в которые я с ним попал.

И так, упрощённая схема моего проекта такова: интернет-магазин, у него есть товары (таблица products), у товаров есть производители, а у производителей есть товары. Ну естественно, товары лежат по категориям, но это пока не настолько интересно. И так, получаем навскидку такие модели:

class Model_Vendor extends ORM {
  protected $_has_may = array ("products"=>array ("model"=>"Product", "foreign_key"=>"vendor_id"));
}

class Model_Product extends ORM {
  protected $_belongs_to = array ("vendor"=>array (
                                    "model"=>"Vendor",
                                    "foreign_key"=>"vendor_id"),
                                                              );
}

Теперь заказчик просит вывести в сайтбаре магазина всех производителей и количество товаров, им выпущенных. И вот первое, очевидное решение (у нас же ORM, хочется его использовать):

foreach (ORM::factory("Vendor")->find_all() as $v) {
  echo "v->name " . $v->products->count_all();
}

(Понятно, что в реальном проекте на Kohana вывод будет отделён от работы с базой, но в статье, ради экономии места, я позволю себе объединить некоторые фрагменты).
На самом деле, до какого-то времени этот код будет работать нормально. Но если у вас, как в моём случае, > 400 000 товаров от сотни-другой производителей, вы вдруг обнаружите, что при отсутствии какой-либо нагрузки на сайт при выводе странички на процессор идёт нагрузка в 30%. И ничего удивительного, если вспомнить, сколько в результате выполняется запросов SQL. Вот здесь лучший выход, который я нашёл — это отказаться для этого подсчёта от услуг ORM. Ведь тоже самое можно сделать всего одним запросам, при помощи группировки полей таблицы products по полю vendor_id. Однако, для построения запроса мы всё равно будем использовать инструментарий Kohana, ниже я расскажу почему.

    $query = DB::select("vendor_id", array (DB::expr("count(id)"), "c"))->from(array("products", "product"))
             ->group_by("vendor_id");

Данный быстрый запрос сразу вернёт количество товара, соответствующего каждому производителю. Можно добавить к этому запросу join с таблицей vendors, и получить таким образом и имена — это уже не так интересно. После этой нехитрой замены при прочих равных условиях нагрузка на процессор при подсчёте количества товаров стала менее 2%.

Поэтому каждое использование инструментов вроде Kohana ORM (или другой ORM) необходимо обдумывать с точки зрения того, что реально происходит

Добавить комментарий

Ваш e-mail не будет опубликован.