Пара фокусов с xPDO
В ходе одного исследования выяснил несколько интересных вещей про xPDO, о которых раньше не задумывался или некогда было проверить.
Решил немедленно поделиться.
В чем же разница?
Внимательный зритель уже догадался в чем трюк — в первом примере мы достаем не объекты, а чистые массивы данных, отсюда скорость и экономия памяти.
Если нужно просто вывести содержимое объектов на экран — то это способ гораздо быстрее.
Обратите внимание, что к полям приписывается имя класса — modResource_ в данном случае. Это можно изменить, используя $q->select('pagetitle');
А если нужно использовать $resource->get(), $resource->set(), $resource->getTVValue() и другие методы объектов — тут второй запрос, помедленнее.
Те же 2 выборки, но с $q->limit(100):
Без объектов:
Память: 17.6 Mb
Время: 0.00191211700439
С объектами:
Память: 23.6 Mb
Время: 0.216797113419
Тут отличие уже не так значительно. Особенно учитывая, что в реальных выводах страниц используется пагинация, и разбивка результатов на 10 — 15 ресурсов за раз.
Те же 2 выборки, но с $q->limit(1); показывают закономерную картину:
Без объектов:
Память: 17.6 Mb
Время: 0.00191211700439
С объектами:
Память: 17.8 Mb
Время: 0.00573897361755
На малой выборке разницы особой нет.
Тут все просто.
Когда вам нужна экономия памяти и высокая производительность для выгрузки товаров, например, или генерации карты солидного сайта — используйте первый метод.
Если же нужны удобства, или размер выборки небольшой — можно не заморачиваться и делать как обычно.
А знаете ли вы, что можно составлять запросы вот так:
А при использовании $modx->newQuery() — будет, он позаботся о правильном составлении запроса согласно модели.
Плюс, newQuery еще дополнительно приведет значения к типам, указанным в модели. То есть, если у вас в модели id указан как int(10), а вы пихаете туда строку — newQuery превратит ее в 0. То есть, приведет к типу int.
Как видно, написание запроса вручную нисколько не экономит время. Но позволяет делать сложные выборки.
Память: 77.8 Mb
Время: 2.14725112915
Ну и самый легкий вариант:
Но разница с ног не сшибает:
Память: 32.7 Mb
Время: 0.0292019844055
Хотя в этом случае не создается здоровенный объект xPDOCriteria.
Видимо, кудесники из MODx что-там хорошо наоптимизировали в своем xPDO.
Вот такие приемы можно использовать в MODx Revolution.
Да, кстати, выборка 3000 ресурсов первым методом проходит за 0.0797028541565 и занимает 64.0.
Вторым — за 6.38202881813 и кушает 194.5 Mb.
Для замера времени использовалась функция microtime(true), для памяти — memory_get_usage(true).
Решил немедленно поделиться.
Выборка 1000 ресурсов
$q = $modx->newQuery('modResource', array('id:>' => 0));
$q->limit(1000);
$q->prepare();
$q->stmt->execute();
$res = $q->stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($res as $v) {
//echo $v['modResource_pagetitle'];
}Этот код работает за 0.042197227478 и занимает 33.3 Mb памяти.$q = $modx->newQuery('modResource', array('id:>' => 0));
$q->limit(1000);
$res = $modx->getCollection('modResource', $q);
foreach ($res as $v) {
//echo $v->get('pagetitle');
}А этот уже за 2.15289998055 и занимает 78.3 Mb памяти.В чем же разница?
Внимательный зритель уже догадался в чем трюк — в первом примере мы достаем не объекты, а чистые массивы данных, отсюда скорость и экономия памяти.
Если нужно просто вывести содержимое объектов на экран — то это способ гораздо быстрее.
Обратите внимание, что к полям приписывается имя класса — modResource_ в данном случае. Это можно изменить, используя $q->select('pagetitle');
А если нужно использовать $resource->get(), $resource->set(), $resource->getTVValue() и другие методы объектов — тут второй запрос, помедленнее.
Выборка 100 ресурсов
Те же 2 выборки, но с $q->limit(100):
Без объектов:
Память: 17.6 Mb
Время: 0.00191211700439
С объектами:
Память: 23.6 Mb
Время: 0.216797113419
Тут отличие уже не так значительно. Особенно учитывая, что в реальных выводах страниц используется пагинация, и разбивка результатов на 10 — 15 ресурсов за раз.
Выборка 1 ресурса
Те же 2 выборки, но с $q->limit(1); показывают закономерную картину:
Без объектов:
Память: 17.6 Mb
Время: 0.00191211700439
С объектами:
Память: 17.8 Mb
Время: 0.00573897361755
На малой выборке разницы особой нет.
Выводы
Тут все просто.
Когда вам нужна экономия памяти и высокая производительность для выгрузки товаров, например, или генерации карты солидного сайта — используйте первый метод.
Если же нужны удобства, или размер выборки небольшой — можно не заморачиваться и делать как обычно.
На закуску
А знаете ли вы, что можно составлять запросы вот так:
$sql = "SELECT * FROM {$modx->getTableName('modResource')} WHERE `id` > 0 LIMIT 1000";
$q = new xPDOCriteria($modx, $sql);
$res = $modx->getCollection('modResource', $q);
foreach ($res as $v) {
//echo $v->get('pagetitle');
}Это тот же второй вариант, с объектами, но SQL запрос составлен в ручную. С одной стороны — вы можете делать так любые выборки, с другой — таккой запрос не универсален, и на Microsoft SQL это работать не будет. А при использовании $modx->newQuery() — будет, он позаботся о правильном составлении запроса согласно модели.
Плюс, newQuery еще дополнительно приведет значения к типам, указанным в модели. То есть, если у вас в модели id указан как int(10), а вы пихаете туда строку — newQuery превратит ее в 0. То есть, приведет к типу int.
Как видно, написание запроса вручную нисколько не экономит время. Но позволяет делать сложные выборки.
Память: 77.8 Mb
Время: 2.14725112915
Ну и самый легкий вариант:
$sql = "SELECT * FROM {$modx->getTableName('modResource')} WHERE `id` > 0 LIMIT 1000";
$q = $modx->prepare($sql);
$q->execute();
$res = $q->fetchAll(PDO::FETCH_ASSOC);
foreach ($res as $v) {
//echo $v['pagetitle'];
}Этот метод отрабатывает уже на чистом PDO, вообще без xPDO объектов.Но разница с ног не сшибает:
Память: 32.7 Mb
Время: 0.0292019844055
Хотя в этом случае не создается здоровенный объект xPDOCriteria.
Видимо, кудесники из MODx что-там хорошо наоптимизировали в своем xPDO.
Вот такие приемы можно использовать в MODx Revolution.
Да, кстати, выборка 3000 ресурсов первым методом проходит за 0.0797028541565 и занимает 64.0.
Вторым — за 6.38202881813 и кушает 194.5 Mb.
Для замера времени использовалась функция microtime(true), для памяти — memory_get_usage(true).
Комментарии: 39
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
Ресурсов: 20000
Памяти скушано: 94.25Мб
Время работы сниппета 0.58 сек
в частности id:>' => 0, тут имеется ввиду значения в столбце айди больше нуля?
И с modResource не понятно — это системная таблица какая-то или что?
Я новичек не могу пока до конца разобраться в xPDO по этому прошу не удивляться сильно моим вопросам))
modResource это модель описывающая структуру таблицы. таблица *table_prefix*site_content
<?php
$modx->addPackage('leleko-cdb', $modx->getOption('core_path').'components/leleko-cdb/model/','leleko_cdb_');
и уже тогда вместо modResource мою модель?
Ничего не выводится… Я пытался и modx_tablename — тоже результата 0.
Из предыдущей заметки
Это вообще кладет сайт с 500й ошибкой
Ага, в этом была проблема, нафиг getTableName только чистое название бд… А на сколько этот метод правильный?
М.б. кто нибудь подскажет ссылочку на статью, для наводки? или пример.
Можно тут pdoTools
Просто получай нужное через get() или используй PDO — там всё прозрачнее.
Получаю массив, но не знаю… верно ли я это сделал, не особо понял зачем $modx->getSelectColumns и для чего указывать 'modResource','modResource', всё это меня смущает и возможно оно работает криво??
даст такой запрос:
А этот:
даст две группы, объединенные оператором OR:
Дополнительную информацию можно посмотреть тут: rtfm.modx.com/xpdo/2.x/class-reference/xpdoquery/xpdoquery.where
Пишу так:
Получаю пустоту [].
вместо
Помогло, что-то вывел), буду дальше пытать.
спасибо.
и выдается следующая структура массива:
Array ( [pagetitle] =>… [introtext] =>… [content] =>… [value] =>… ) т.е. почему-то на псевдонимы не заменяются названия таблиц, и из-за одинаковых полей работает только последний джоин. Как можно этого избежать?
Это можно писать вручную, а можно использовать сниппеты pdoTools и методы самой библиотеки.
Офигенно релевантный запрос. Зато обрати внимание, что с твоим комментарием эта тема сразу оказалась на третьем месте и здесь и в яндексе.
P.S. На сайте есть еще bezumkin.ru/index для таких интересных статей. В верхнем меню — первая кнопка.
Мой сайт построен целиком на MODX и компоненте Tickets. Здесь пока нет избранного, но когда-нибудь, возможно, и появится.
Мне вообще кажется неправильным строить сайты для модыксеров на базе неMODX решений.
И пока не забыл — отчего-то msOrder параметр tplSuccess забирает, только если прописать в дефолтных настройках. В вызове &tplSuccess=`bla-bla` не понимает.
На всякий случай — в браузерах дааааавно есть такая функция.
Но все же, как интересно было бы смотреть чужое избранное, к примеру, что Илья Уткин подчерпнул ценное на сайте, и что занес в избранное? Кстати, статистика статей добавленных в избранное покруче будет рейтинга — новый критерий для «веса» в поиске.
PS: цена вопроса?
Постараюсь доработать на досуге и причесать всё, чтобы было в одном стиле с уже написанным.
Спасибо!