Пара фокусов с xPDO в MODx Revolution

в 3:53, , рубрики: modx, modx revolution, xpdo, метки: ,

Пара фокусов с xPDO в MODx Revolution
В ходе одного исследования выяснил несколько интересных вещей про xPDO, о которых раньше не задумывался или некогда было проверить.

Кто ничего не знает про xPDO — советую глянуть эту статью.

Если вкратце — это сама основа Revolution. Вся работа CMF построена на нем, и даже класс MODx наследуется от класса xPDO.

Выборка 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).

Автор: bezumkin

  1. svoy:

    Спасибо, очень помог “самый легкий вариант” для составления запроса к нескольким базам. Все же чистый sql проще в понимании )

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js