Query Builder vs конкатенация запроса ручками

На какой стороне ты?

  • QB / ORM / etc

    Голосов: 18 78,3%
  • Пилю все ручками, не обламываюсь.

    Голосов: 5 21,7%
  • ЭОС

    Голосов: 0 0,0%

  • Всего проголосовало
    23

Вурдалак

Продвинутый новичок
вызорва метода объекта в стиле (new app_db())->, а не костылем в виде вызова статического метода класса, с передачей области видимости объекта методу, который вообще не должен ничего знать об этом объекте?
ахаха, какой наивный юноша. Написание (new Foo)-> ничем не лучше Foo::.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Ваш параметр не учитывает SQL_CALC_FOUND_ROWS для MySQL. наверное в вашем qb это учтено?
Это синтаксический сахар, учет которого делается таким же сахаром в QB, вопрос давно решен.
Прикол в том, что с ростом базы эти запросы начинают класть сервер, их приходится переписывать без SQL_CALC_FOUND_ROWS.

Сделайте такой мне SQL через билдер (поиск маршрута движения от остановки "с" до остановки "д" по маршруту от точки "а" до точки "б").
не проблема совершенно, в этом sql ничего сложного

фильтр типа "и" для каталога по разным параметрам с возможностью выбора нескольких возможных значений для одного параметра , explain про индексы ниже
сделали :) на ActiveRecord неожиданно оказалось очень удобно.
EAV по товарам в категориях в каталоге раскладывается на 10 таблиц. В каталоге магазина надо выполнять десяток-другой довольно похожих запросов, в котором всегда есть такой условный кусок:
Код:
FROM products INNER JOIN products_x_categories INNER JOIN categories
WHERE products.status = 'in_store' AND products.quantity >0 AND categories.status = 'active' AND categories.visibility =1
На практике довольно большой кусок выходит.

При разных запросах пользователя сюда надо добавить разные join-ы и условия: фильтр по производителю, сортировrа по цене, фильтры по свойствам.
Вот этот общий кусок запроса формируется в отдельном методе QB/AR в базовой модели, а в конечных методах в него добавляются нужные условия.
В принципе, разделение текста запроса на разные методы - не очень хорошо.
Но в текстовый SQL новый JOIN не добавить, а когда заготовок запроса в виде объекта - очень даже можно.
Дебажить огромные запросы становится намного проще - нет опечаток.

Типичные селекты по одному параметру конечно можно дергать, но представим в чем его преимущество перед SQL запросом, написанном в строчке?
В скорости.
PHP:
$post = Posts::model()->cache()->findByPk($post);
echo $post->author->name;
пишется в разы быстрее, чем
Код:
//ручками пишем кеширование
$q = "select * from posts where posts.(какое поле тут ключ? надо глянуть структуру) =:post limit 1";
$p = $DB->query(['post'=>$post]);
$q = "select * from users where users.(какое поле тут ключ? надо глянуть структуру) =:user limit 1";
$DB->query(['user'=>$p['по какому полю идет связь? надо глянуть структуру!']]);
потому что без опечаток, без дебага, все поля и связи в автокомплите.

Ни один ОРМ не "построит (build)" подобный SQL, который из 500K товаров и 6M параметров с доп выборками по нескольким категориям, учитывая не только вариации фильтра, но и признак общедоступности, который вытянет 2 строки за 0.01 сек
о, да, расскажи что еще я делал невозможного :)
не хочу сказать, что это было очень просто, да, патч на USE KEY мы писали,
и в итоге просто переписали ActiveRecord.

where ".($onlyPublic ? "`app_catalog_item`.`public` = '1' and (" : null)." `categoryId` IN ('".implode("', '", $array)."') ".($onlyPublic ? ")" : null)."
Для этого и нужен орм.
как-бы да, этот код становится читабельным
 
Последнее редактирование:

Активист

Активист
Команда форума
ахаха, какой наивный юноша. Написание (new Foo)-> ничем не лучше Foo::.
с какого это ничуть ни лучше?)) В первом случае создается объект, во втором выполняется статичный метод с передачей области видимости, разницу вы должны знать и понимать.
 
Последнее редактирование:

Активист

Активист
Команда форума
о, да, расскажи что еще я делал невозможного :)
не хочу сказать, что это было очень просто, да, патч на USE KEY мы писали,
и в итоге просто переписали ActiveRecord.
//
какое поле тут ключ? надо глянуть структуру
Вот именно в этом. Если вы используете библиотеку - то должны ее использовать так, как она есть, и если ее возможности не отвечают вашим потребностям, то по норме - вы вкладываете в эту библиотеку код и выпускается новая версия, или вы отказываетесь от ее использования.

Это я к тому, что мне достаточно знать особенности SQL того или иного SQL сервера, и я могу четко и сразу изменить сам запрос, а если это обернуто в какую либо библиотеку, то мне придется изучить ее документацию, а если там внесены недокументированные изменения - то это заставит меня еще и разобраться с этой библиотекой.

Выигрываете ли вы на скорости кодинга (именно кодинга), можно еще поспорить. А смотреть в структуру БД нужно, что бы хотя бы знать есть ли индексы , и используются ли они при выборках.

А по поводу затыков SQL_CALC_FOUND_ROWS - обновить MySQL Engine ))
 

AmdY

Пью пиво
Команда форума
Вот, кстати, ещё один плюс qb и orm, привыкаешь не писать write only код. к сожалению, мне приходилось поддерживать такой код http://phpclub.ru/talk/threads/query-builder-vs-конкатенация-запроса-ручками.78381/page-2#post-707218 это ад, его прочесть невозможно, не говоря уже о модификации и тестировании.
При наличии qb, все джойны и условия вынеслись бы в методы с говорящими названиями, которые можно читать без километра переписки и поисков по внутренней вики.
PHP:
"
                select
                    *
                from
                    `root_bricks`          
                left join
                    `root_info` on `root_bricks`.`root_id` = `root_info`.`id`
                left join
                    `schedule`  on `root_bricks`.`root_id` = `schedule`.`root_id`
                right join
                    `carriers`  on `carriers`.`id` = `root_bricks`.`carrier_id`
                right join
                    `root_nodes` as `begin_node` on `root_bricks`.`root_id` = `begin_node`.`root_id` && `root_bricks`.`begin_point` = `begin_node`.`begin_point` -- @todo убрать из sql в будущем, разобравшись в коде
                right join
                    `root_nodes` as `end_node` on `root_bricks`.`root_id` = `end_node`.`root_id` && `root_bricks`.`end_point` = `end_node`.`end_point`          
                where
                    `schedule`.`dispatch_date` = '".$datetime->format("Y-m-d")."'
                    and `root_bricks`.`cost` > 0
                    and    `root_bricks`.`begin_point` = '".$db->escape($dispatchStation)."'
                    and    `root_bricks`.`end_point` = '".$db->escape($arrivalStation)."'
                    and `begin_node`.`order` <= `end_node`.`order`
                order by
                    `schedule`.`dispatch_datetime`
            "
// при наличии qb он бы писался в стиле
$bricks
  ->withInfo()
  ->withSchedule()
  ->withCarriers()
  ->withNodeBegin()
  ->withNodeEnd()
      ->whereDispatch(new DateTime())
      ->whereHasCost()
      ->whereBricksBetween(..., ...)
->orderBy('dispatch_datetime');
 

Активист

Активист
Команда форума
Вот, кстати, ещё один плюс qb и orm, привыкаешь не писать write only код. к сожалению, мне приходилось поддерживать такой код http://phpclub.ru/talk/threads/query-builder-vs-конкатенация-запроса-ручками.78381/page-2#post-707218 это ад, его прочесть невозможно, не говоря уже о модификации и тестировании.
При наличии qb, все джойны и условия вынеслись бы в методы с говорящими названиями, которые можно читать без километра переписки и поисков по внутренней вики.
PHP:
"             
// при наличии qb он бы писался в стиле
$bricks
  ->withInfo()
  ->withSchedule()
  ->withCarriers()
  ->withNodeBegin()
  ->withNodeEnd()
      ->whereDispatch(new DateTime())
      ->whereHasCost()
      ->whereBricksBetween(..., ...)
->orderBy('dispatch_datetime');
Вопрос, сколько времени нужно потратить, что бы настроить qb правильно делать этот запрос, при том, что он будет использован лишь раз?
 

Активист

Активист
Команда форума
Потому что классо-ориентированное программирование и объектно-ориентированное программирование - разные вещи))

Синтаксис:
PHP:
$db = db::query($sql, $data);
и
PHP:
$db = (new app_db())->query($sql, $data);
Вроде бы не сильно отличается, но вдруг понадобилось расширение проекта и четыре SQL сервера с репликацией. Один master (rw only) и три slave (ro only) в разных ЦОД'ах. С объектом я по меньшей мере могу работать как угодно именно с экземляром объекта, а не со статичным методом.

PHP:
$affected_rows = (new app_db())->use_rw_connection()->query("insert into")->affected_rows();

$rows = (new app_db())->use_ro_connection()->switch("Europe/Moscow")->query("select ...")->fetch_all();
Поэтому синтаксис (new classname()) очень уж помог с 5.4
 
Последнее редактирование:

fixxxer

К.О.
Партнер клуба
PHP:
class app_db {

   public static function __callStatic($method, array $args) {
        return call_user_func_array([new static, $method], $args);
   }

}
$affected_rows = app_db::rw_connection()->query("insert into")->affected_rows();

то же самое. Начинаешь понимать? ;)
 

Активист

Активист
Команда форума
PHP:
class app_db {

   public static function __callStatic($method, array $args) {
        return call_user_func_array([new static, $method], $args);
   }

}
$affected_rows = app_db::rw_connection()->query("insert into")->affected_rows();

то же самое. Начинаешь понимать? ;)
Нет, смотри внимательно. Мой коммент был к
PHP:
$db = db::query($sql, $data);
ты же привел реализацию абстрактной фабрики через вызов статического метода.
 

fixxxer

К.О.
Партнер клуба
Не, ты не понимаешь, о чем речь. :)

class MyDb extends app_db, дальше что?
 

Активист

Активист
Команда форума
Еще раз, уточняю обсуждаемый кусок:
PHP:
$db = db::query($sql, $data);
Как мы тут можем заюзать "class MyDb extends app_db" ? Или через неявный магический метод __callStatic ?
 

Вурдалак

Продвинутый новичок
В первом случае создается объект, во втором выполняется статичный метод с передачей области видимости, разницу вы должны знать и понимать.
Ты вкладываешь в понятие «передача области видимости» что-то своё. Передача области видимости была бы, если бы в статическом методе мы бы могли свободно использовать переменные из контекста вызова. Вот это «передача области видимости».

Твой код с (new Foo)-> яйца выеденного не стоит без DI. Обычный singleton. А писать (new Foo) или Foo::getInstance() или даже Foo::bar() — это тут уже не столь принципиально. Я вижу ты любишь fluent interface, но архитектурно тут 0 отличий.
 

Активист

Активист
Команда форума
Ты вкладываешь в понятие «передача области видимости» что-то своё. Передача области видимости была бы, если бы в статическом методе мы бы могли свободно использовать переменные из контекста вызова. Вот это «передача области видимости».

Твой код с (new Foo)-> яйца выеденного не стоит без DI. Обычный singleton. А писать (new Foo) или Foo::getInstance() или даже Foo::bar() — это тут уже не столь принципиально. Я вижу ты любишь fluent interface, но архитектурно тут 0 отличий.
Ахахахаха.... Где вы нашли синглтон??? Я вам про адаптер, вы мне про синглтон)) Вы везде видите синглтон?))) А писать в стиле "fluent interface", да, мне это нравится, удобно.
В при вызове someclass::some_method($string, $data) область видимости передается, а далее в some_method для его расширения можно костылей понаделасть, что хрен разберешься.

От функций какое отличие?
somenamespace\some_function($string, $datа)
 

AmdY

Пью пиво
Команда форума
Вопрос, сколько времени нужно потратить, что бы настроить qb правильно делать этот запрос, при том, что он будет использован лишь раз?
Практически каждый метод реиспользуемый и при наличии qb пишется чуть дольше твоей простыни, а если есть условия, то выигрыш будет изначально. Получаем удобный и читаемый код, который легко поддерживать без всякой документации.

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

Вурдалак

Продвинутый новичок
Где вы нашли синглтон?
PHP:
protected static $_mysqli;
// ...
    if (!isset(self::$_mysqli))
    {
// ...
      self::$_mysqli=new mysqli(
Фанат с таким же успехом может написать
PHP:
db::setAdapter(new app_db_mysqli());
И таки да, твой код — это синглтон головного мозга, просто ты не в состоянии этого понять. У тебя всё держится на static'ах и глобальном состоянии. Сколько говнецо не прикрывай, а лучше от (new Foo) код не станет.

По поводу области видимости — это вообще клиника, почитай там Википедию, разберись с этим понятием. Куда там и что у тебя передаётся.
 
Сверху