Разделы

Прямой эфир

Весь эфир | RSS

Оптимизация PHx - убираем лишние запросы к БД

На modxcms.com пользователь tobice столкнулся с проблемой чрезмерно большого количества обращений к БД.
В результате выяснилось, что в плагине PHx содержится досадная ошибка, которая приводит к 1 дополнительному запросу к БД при каждом вызове phx-сниппета. К примеру, если вы используете Дитто, то вы получите по N дополнительных запросов на каждую итерацию (в случае некешируемого вызова)!
Исходный топик:
110 mysql requests for one page loaded from cache! Is it too much?!

Решение:
PHx не использует штатный метод MODx API modx->runSnippet(), и как следствие, не использует кеш MODx для хранения кодов своих сниппетов.
Однако, в PHx все же реализовано кеширование, но с ошибкой, из-за которой оно не работает.
Я внес изменения в файл /assets/plugins/phx/phx.parser.class.inc.php, которые позволяют phx использовать системный кеш $modx->snippetCache и не порождать лишние запросы к БД.

На одном проекте я уже применил этот патч, уменьшив количество запросов на 10-50 шт. на страницах (и там еще есть, куда оптимизировать).

Прикладываю пропатченный файл с изменениями из моего комментария, которые позволяют phx использовать системный кеш сниппетов. Это максимально возможная оптимизация phx по использованию БД.

Файл: phx.parser.class.inc.php (пропатченный)
Класть сюда: /assets/plugins/phx/phx.parser.class.inc.php

Комментарии (37)

RSS свернуть / развернуть
0
Спасибо, весьма полезно.
avatar

NevroZ

  • 14 июня 2010, 11:36
0
Забавно. Получается эта ошибка есть во всех сниппетах использующих свой встроенный PHx?
avatar

elastic

  • 14 июня 2010, 17:15
0
Удивительно, что этот глюк прожил столько времени.

PS: кат, плиз. Тема, очевидно, выйдет на главную.
avatar

Carw

  • 14 июня 2010, 19:06
0
уже есть 2.1.4, там это исправлено?
avatar

Dronowar

  • 15 июня 2010, 13:36
0
не знаю, в данный момент в репозитории архив с phx не скачивается.
avatar

antonkuzmin

  • 15 июня 2010, 18:17
0
Сейчас скачивается, дайте свою оценку производительности свежей версии =)
avatar

pitbull

  • 24 июня 2010, 18:29
+1
код, отвечающий за работу кастомных phx-сниппетов не изменился, за исключением дополнительного условия для обработки ошибок.
avatar

antonkuzmin

  • 24 июня 2010, 21:08
0
Чудненько… 3 года без обновлений и с такой ошибкой пропустили новую версию… печально.
avatar

pitbull

  • 24 июня 2010, 21:15
0
да и выложите готовый файл чтобы не лазить лишний раз
avatar

Dronowar

  • 15 июня 2010, 13:42
+4
Я доработал предложенное решение так, чтобы PHx использовал стандартный кеш сниппетов для хранения своих модификаторов. Это дополнительно уменьшает лишние запросы к базе на величину, равную количеству используемых кастомных модификаторов на странице (в моем случае получилось минус 5-7 запросов к БД на страницу). Дело в том, что все сниппеты (в том числе и используемые в phx) де факто хранятся в кеш-файле и не требуют загрузки из БД.

Вот модифицированный фрагмент из поста:

$snippetName = 'phx:'.$modifier_cmd[$i];
if (isset($modx->snippetCache[$snippetName])) {
	$snippet = $modx->snippetCache[$snippetName];
} else { // not in cache so let's check the db
	$sql = "SELECT snippet FROM " . $modx->getFullTableName("site_snippets") . " WHERE " . $modx->getFullTableName("site_snippets") . ".name='" . $modx->db->escape($snippetName) . "';";
	$result = $modx->dbQuery($sql);
	if ($modx->recordCount($result) == 1) {
		$row = $modx->fetchRow($result);
		$snippet = $modx->snippetCache[$row['name']] = $row['snippet'];
		$modx->Log("  |--- DB -> Custom Modifier");
	} else if ($modx->recordCount($result) == 0){ // If snippet not found, look in the modifiers folder
		$filename = $modx->config['rb_base_dir'] . 'plugins/phx/modifiers/'.$modifier_cmd[$i].'.phx.php';
		if (@file_exists($filename)) {
			$file_contents = @file_get_contents($filename);
			$file_contents = str_replace('<'.'?php', '', $file_contents);
			$file_contents = str_replace('?'.'>', '', $file_contents);
			$file_contents = str_replace('<?', '', $file_contents);
			$snippet = $modx->snippetCache[$snippetName] = $file_contents;
			$modx->snippetCache[$snippetName.'Props'] = '';
			$modx->Log("  |--- File ($filename) -> Custom Modifier");
		}
	}
}
$cm = $snippet;

Подскажите, куда лучше загрузить патченный файл phx.parser.class.inc.php?
avatar

antonkuzmin

  • 15 июня 2010, 22:41
0
Да можно прямо в этот топик файл пристегнуть, чтобы все было в одном месте.
avatar

Carw

  • 15 июня 2010, 23:13
+1
Обновил пост, прикрепил патченный файл.
avatar

antonkuzmin

  • 18 июня 2010, 18:42
+1
Вы бы как-то поправили название поста. Откуда взялись «100 лишних запросов»??? Если у какого-то чела с кривыми руками так получается, это не значит, что у всех так будет. Этим вы отпугиваете людей от использования MODx.
avatar

Andchir

  • 21 июня 2010, 13:35
0
Куда смотрит админ?
avatar

Andchir

  • 21 июня 2010, 13:36
0
Если чел ставит 5 вызовов phx в шаблон Дитто, предполагая, что они не будут каждый раз запрашиваться из базы, у него кривые руки? :)
Вообще-то если смотреть на Друпал, там может и 600 запросов к базе возникнуть на пустом месте, и это не кривые руки виноваты, да и друпальщиков от этого меньше не становится )

А постом своим я совершаю совершенно обратную операцию. Знаете ли, лучше дать возможность разработчикам сразу узнать, почему сайт глохнет от 10 одновременных пользователей и это исправить, чем в неведении они просто мигрируют «с этой неповоротливой modx» на какую-нибудь джумлу )
avatar

antonkuzmin

  • 21 июня 2010, 18:55
0
к тому же это действительно epic fail — на устранение этого бага у меня ушло от силы полчаса, а баг этот весьма существенный и существовал годами. страшно представить, сколько сайтов используют неработающее кеширование phx, в уверенности, что оно работает :)
avatar

antonkuzmin

  • 21 июня 2010, 18:57
0
Если человек сделал сайт и у него на странице получилось больше 100 запросов (даже если больше 30-ти), это значит у него кривые руки. И не важно из-за чего это произошло. Из вашего заголовка выходит, что патч «убирает» около 100 запросов. 100* это в данном конкретном случае. Страница кэшированная, но Дитто вызывался некэшированным и в шалоне использовались PHx-модификаторы. PHx в шаблоне некэшированного Ditto это по определению нерационально и очень медленно.
avatar

Andchir

  • 21 июня 2010, 20:08
0
Но пост безусловно очень полезный. Спасибо Вам за него!
Мне только заголовок не понравился :)
avatar

Andchir

  • 21 июня 2010, 20:11
0
Я согласен — заголовок желтоват. Тема и без него очень интересна и важна.
avatar

Carw

  • 21 июня 2010, 20:35
0
Исправил заголовок на более нейтральный, правда боюсь теперь кто-то может пройти мимо поста.
Моя деятельность частично пересекается с рекламой и маркетингом, поэтому меня во фразе «до 100» ничего не смущает :)
avatar

antonkuzmin

  • 21 июня 2010, 22:45
+3
Всех не спасти ;-)
avatar

Carw

  • 21 июня 2010, 22:58
+1
заменил файлик на тот что есть. в итоге:
Fatal error: Call to undefined method DocumentParser::Log() in /home/virtwww/w_nnttv-ru_29ecd83e/http/assets/plugins/phx/phx.parser.class.inc.php on line 311
avatar

Dronowar

  • 23 июня 2010, 13:45
0
Действительно, в файле ошибка. Верните пока старую версию, я выложу исправленную версию чуть позже.
avatar

antonkuzmin

  • 23 июня 2010, 16:10
+2
Исправлено. Я обновил файл, прикрепленный к топику. Попробуйте его на своем проекте — все должно работать.
Советую также замерить количество запросов с исходной версией и с обновленной — для этого в любом месте надо написать тег [^q^]
avatar

antonkuzmin

  • 23 июня 2010, 16:31
0
Заменил код.

Результаты следующие

//non-optimized phx
S:database | QT:1.8135 s | Q:227 | P:8.0063 s | T:9.8198 s

//optimized phx
S:database | QT:0.6842 s | Q:228 | P:5.1530 s | T:5.8372 s

Количество запросов не уменьшилось, уменьшилось время. Но это еще может зависить от нагрузки на сервер. По-этому я так понимаю у меня не сработало:(
avatar

kollad

  • 25 июня 2010, 13:51
0
в у вас успользуются модификаторы phx в виде снипетов? только эта часть затронута, остальные без изменения.
avatar

tonatos

  • 25 июня 2010, 14:19
0
228 запросов!? Что у вас там используется?
avatar

Carw

  • 25 июня 2010, 14:30
0
сейчас у вас на главной странице показывается 18 запросов :)
на внутренних в первый раз — больше 100, после перезагрузки страницы — сокращается до пары десятков.
avatar

antonkuzmin

  • 25 июня 2010, 18:15
0
там пи… ц:))

Во-первых был такой кусок, для построения левого меню навигации

[+phx:if=`[[Ditto? id=`sub[+id+]` &parents=`[+id+]` &filter=`isfolder,1,1` &noResults=`nochilds`]]`:isnot=`nochilds`:then=`<ul>[[Ditto? id=`sub[+id+]` &parents=`[+id+]` &display=`all` &save=`1` &tpl=`subcatalog_tplLeft` &filter=`isfolder,1,1` &noResults=` ` &sortBy=`menuindex` &sortDir=`ASC` ]]</ul>`:else=``+]

Это делал давно, и видимо для того, чтобы не создавались пустые <ul></ul>, если в документе нету подраздела(подкаталога)…

Сейчас в целях оптимизации, оптимизировал этот кусок, а точнее убрал PHx, и оставил только

<ul>[[Ditto? id=`sub[+id+]` &parents=`[+id+]` &display=`all` &save=`1` &tpl=`subcatalog_tplLeft` &filter=`isfolder,1,1` &noResults=` ` &sortBy=`menuindex` &sortDir=`ASC` ]]</ul>

Количество запросов уменьшилось вдвое:) уже радует:) сейчас вообще пишу свой сниппет, для создания каталога… Потому что дитто уже слишком тяжелый для моего сайта-магазина…

Кому интересно посмотреть что там — sunnyland.com.ua
внизу в футере данные по загрузке страницы
avatar

kollad

  • 25 июня 2010, 15:45
0
Может рассмотрите SBShop 0.1a? Заодно оптимизируем под большой объем, что все равно меньше времени затратит, чем писать заново каталог. :-)
avatar

Carw

  • 25 июня 2010, 16:44
0
Я бы с радостью, но магазин уже работает, в нем около 3800 позиций — и это только товары. И для того, чтобы мигрировать на другое решение, нужно будет немало времени на перенос потратить.

А каталог в принципе довольно быстро пишется, я беру все те же шаблоны, что используются в Ditto, то-есть принцип работы, шаблоны и тд. остается прежним, просто для построения каталога, у меня будет не огромно количество запросов, как делает Ditto, а одним запросом из базы)
avatar

kollad

  • 25 июня 2010, 18:07
0
Ну может быть. Тут все зависит от того, как все устроено сейчас. В SBShop тоже все с шаблонами и суть их схожа (контейнер / ряд), но вот параметры работают совсем по другому.
avatar

Carw

  • 25 июня 2010, 18:11
0
Ага, а потом захочется добавить комментирование к товарам или рейтинги и надо писать с нуля или править то что есть у MODx :)
avatar

Andchir

  • 25 июня 2010, 20:14
0
Это правда. Тот же jot придется привязать к другой таблице, если возникнет желание комментировать через него.
avatar

Carw

  • 25 июня 2010, 20:58
0
В любом случае, я Ваше решение возьму на вооружение, и на локальном сервере буду в нем ковыряться:) И возможно в дальнейшем перепрыгну на него:)
avatar

kollad

  • 25 июня 2010, 18:16
0
Отлично, появится возможность повозиться с оптимизацией. 3800 товаров — уже неплохо. Кстати, как обновляете цены / информацию? Все ручками или как-то автоматизированно?
avatar

Carw

  • 25 июня 2010, 19:21
0
Полу автомат:) Написал скрипт импорт/сравнение база/прайс:)
avatar

kollad

  • 29 июня 2010, 16:15

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.