И как у этого велосипеда с производительностью на больших объёмах данных?<br><br><div class="gmail_quote">26 октября 2011 г. 18:26 пользователь Ivan Petrov <span dir="ltr"><<a href="mailto:i.petro.77.00@gmail.com">i.petro.77.00@gmail.com</a>></span> написал:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">сделали мы тут цельный проект на DBIx::Class. С точки зрения<br>
попробовать последний. До этого всегда использовали DBI, который<br>
использовала модель в системе MVC.<br>
<br>
Впечатления плохие, однако появились мысли куда надо двигаться чтобы<br>
было хорошо. Я их тут изложу, а вы покритикуйте.<br>
<br>
В первую очередь зачем как бы нужен был этот DBIC.<br>
 - конструирование SQL-запросов<br>
 - уход от смешивания кода Perl с кодом SQL<br>
 - выборка объектов, а не хешей из БД, которые можно расширять своими<br>
   методами<br>
 - упрощение кода моделей с точки зрения что в простых случаях вообще<br>
   не делать выделенную модель<br>
<br>
Ничего не забыл?<br>
<br>
По результатам проекта (проект был довольно большой и дальше еще будет<br>
долго) я понял следующее:<br>
<br>
1. даже в простых случаях DBIC на роль модели не годится. То есть в<br>
любом случае нужно делать выделенную модель, пусть даже там один<br>
resultset('Name')->find. Ибо тесты. При их написании мы применяем<br>
способ "подменить модель на стадии тестирования".<br>
<br>
2. DBIC не предоставляет хорошей абстракции над БД. Все равно<br>
JOIN'ы, SELECT'ы торчат местами (например join_type => 'left' в has'ах<br>
итп). То есть оперировать хранилищем как некоей абстракцией в реальном<br>
случае не получается.<br>
<br>
3. Конструктор SQL-запросов крайне страшен. Работали мы с постоянно<br>
включенной отладкой (выводом всех делающихся запросов в лог). С одной<br>
стороны есть множество вещей которые на DBIC сделать крайне непросто<br>
(например многие аггрегаторные вещи), с другой стороны когда<br>
начинается работа с более чем двумя таблицами он зачастую мутит такие<br>
страшные вложенные SQL-запросы что волосы дыбом становятся, а с<br>
третьей стороны использование фич конкретной БД становится затруднено.<br>
<br>
В итоге пришли к тому, что в сложных случаях приходится делать в БД<br>
view'ы только из за того что от DBIC добиться генерации нормального<br>
запроса очень и очень сложно или невозможно. Набор опций при выборке<br>
может быть больше самого SQL-запроса, если его просто написать.<br>
<br>
Ну вот и в свете того, что код работы с DBIC все равно располагается в<br>
моделях, конструировать эффективные SQL-запросы он все равно не умеет,<br>
то из плюсов его использования остаются только:<br>
 - выборка в объекты и итераторы по ним<br>
 - уход от смешивания Perl и SQL<br>
<br>
Соответственно размышляя над всем этим мы пришли к тому, что<br>
<br>
1. построить качественный автогенератор SQL запросов на все случаи<br>
жизни (или по кр. мере на большинство) невозможно, поэтому его не<br>
стоит и пытаться сделать<br>
<br>
2. из за п.1 бОльшая часть DBIC становится не нужна, а надо делать<br>
некоего помощника, который бы человеку просто помогал удобно работать<br>
с БД.<br>
<br>
то есть надо<br>
<br>
1. написать свой итератор, работающий поверх массива или<br>
хеша - выборки из БД.<br>
2. написать базовую обертку над одной строкой выборки (доступ в виде<br>
методов)<br>
3. Используя 1 и 2 написать над DBI класс, который выборки блессает в<br>
итераторы и объекты<br>
4. решить вопрос с выносом SQL-кода из перловых модулей. То есть<br>
обертка 3 должна уметь работать с SQL, располагающимися в файлах.<br>
<br>
<br>
Вынос SQL в файлы очень плохо соотносится с дефолтными плейсхолдерами<br>
DBI. поскольку они позиционные.<br>
<br>
Вывод:<br>
5. надо реализовывать именованные плейсхолдеры<br>
<br>
ну и попутно<br>
5.1 реализовать плейсхолдерные (темплейтные) выражения для типовых<br>
вещей, как-то<br>
 INSERT ... VALUES (?,?,?),(?,?,?),(?,?,?),...<br>
<br>
или<br>
 SELECT ... WHERE id IN (?,?,?)<br>
<br>
то есть подстановки массивов.<br>
<br>
Соответственно исходя из этого родился набор модулей, который в<br>
ближайшее время, если кому-то будет интересно, мы можем выложить на<br>
CPAN (там еще работы на неск. дней осталось), который все это делает:<br>
<br>
1. по дефолту блесает строки-выборки в объект, у которого три<br>
предопределенных метода: new, is_changed, iterator. Плюс методы<br>
совпадающие с именами выбранных столбиков.<br>
<br>
2. блесает наборы-выборки в объект позволяющий делать проходы по<br>
выборкам итп (совместимо с DBIC'шными ->all, while(...->next) итп<br>
<br>
3. в п. 1 и 2 позволяет указывать свои классы для итераторов и выборок<br>
<br>
4. позволяет вместо SQL использовать имена файлов SQL в предзаданной<br>
директории (по аналогии с темлейтами любого вебпроекта)<br>
<br>
5. реализует следующий набор подстановок в SQL<br>
<br>
    ?{путь} - просто подставляет переменную<br>
    ?@{путь} - подставляет массив переменных (через запятую)<br>
    ?%{путь}{поле,поле,...} - подставляет массив переменных (через<br>
          запятую) из массива хешей<br>
<br>
    ну и на вс случай сделали<br>
    ?sub{перловый код}<br>
<br>
<br>
    А так же набор условных подстановок вроде<br>
<br>
    ?if[de]?{путь}{ блок который вставится }{else-блок}<br>
<br>
    условия - if - истина<br>
              ifd - определен<br>
              ife - имеется<br>
<br>
   Блоки можно вкладывать друг в друга.<br>
<br>
   пути - по сути путь к переменной во входном хеше, то есть<br>
<br>
   $dbh->do($sql, values => { ids => [1, 3, 5] }, abc => 'def');<br>
<br>
   путями являются<br>
   'values'<br>
   'abc'<br>
   'values.ids'<br>
<br>
   и так далее.<br>
<br>
   поддерживаются в путях и объекты<br>
<br>
   path.to:method  - будет вызван метод объекта, а значение им<br>
   возвращенное будет вставлено в SQL.<br>
<br>
<br>
В итоге что получили:<br>
<br>
1. SQL вынесен в отдельный каталог (отдельные каталоги) примерно так<br>
же как вынесены темплейты в любом вебпроекте<br>
2. типичные SQL-вещи делаются просто. Сложные тоже можно делать.<br>
3. Поскольку итератор по именам методов постарались сделать<br>
совместимым с DBIC то замена одного на другое не вызывает больших<br>
трудностей.<br>
<br>
ну и возьмем пример:<br>
<br>
скажем приходит от пользователя форма<br>
<br>
$filters = { region => 'Москва', street => '' };<br>
<br>
То есть он фильтр по региону заполнил, а фильтр по улице нет<br>
<br>
запрос может выглядеть так<br>
<br>
SELECT<br>
    *<br>
FROM<br>
    tbl1<br>
LEFT JOIN tbl2 ...<br>
<br>
WHERE<br>
    something = ..<br>
<br>
    ?if{filters.region}{ AND region = ?{filters.region} }<br>
    ?if{filters.street}{ AND street = ?{filters.street} }<br>
<br>
и так далее.<br>
<br>
Получается SQL перестраивается в зависимости от того что там вводит<br>
пользователь.<br>
<br>
Осталось нерешенными некоторые типовые вопросы, но мы их планируем<br>
порешать в ближайшее время (например подставновки частей в<br>
like-секции)<br>
<br>
соответственно вопросы:<br>
<br>
1. кому-нибудь интересна подобная система, стоит класть на CPAN?<br>
2. может на эту тему есть что-то готовое да мы велик очередной ваяем?<br>
тогда ткните указкой:)<br>
<font color="#888888">--<br>
Moscow.pm mailing list<br>
<a href="mailto:moscow-pm@pm.org">moscow-pm@pm.org</a> | <a href="http://moscow.pm.org" target="_blank">http://moscow.pm.org</a><br>
</font></blockquote></div><br><br clear="all"><br>-- <br>Andrei Protasovitski<br>< andrei[dot]protasovitski[at]gmail[dot]com ><br>Diemen, Netherlands<br>