Итак, у вас тысяча ресурсов на сайте и вам нужно сгенерировать карту Google для сайта. С несколькими сотнями ресурсов, вы можете использовать некоторые из дополнений из репозитория (getResources, GoogleSiteMap, pdoSitemap) и при этом не будет никаких проблем с производительностью. Но что будет, если у вас 15 тыс. ресурсов?
Ответ простой, необходимое время для генерации ресурсов быстро увеличивается и вы начинаете быстро подходить к границе памяти и времени выполнения скриптов PHP. На последнем сайте, с которым я работал, пришлось решать именно эту проблему. И на ум мне прошло самое простое решение!
После обдумывания различных процессов оптимизации, я быстро понял, что получение количества ресурсов и последующая их итерация для получения нодов была слишком расточительной - две с половиной минуты это слишком. Поэтому я установил способ, при котором нет нужды проходить повторно через ресурсы и это было достигнуто тем, что мой код генерировал вывод XML нода. Законченный сниппет будет иметь следующий вид:
`<?php ini_set(‘max_execution_time’, 0);
$priority = $modx->getOption(‘priorityId’, $scriptProperties, 1); $changeFreq = $modx->getOption(‘changeFreqId’, $scriptProperties, 1);
$options = array( xPDO::OPT_CACHE_KEY => ‘sitemap’, ); $output = $modx->cacheManager->get(‘sitemap’, $options);
if ($output == null) {
$output = ‘
$stmt = $modx->query("
SELECT
GROUP_CONCAT(
'<url>',
CONCAT('<loc>" . MODX_SITE_URL . "',uri,'</loc>'),
CONCAT('<lastmod>',FROM_UNIXTIME(editedon, '%Y-%m-%d'),'</lastmod>'),
IFNULL(
CONCAT('<priority>',(
SELECT value
FROM modx_site_tmplvar_contentvalues
USE INDEX (tv_cnt)
WHERE contentid=id AND tmplvarid={$priorityId}
),'</priority>'),''),
IFNULL(
CONCAT('<changefreq>',(
SELECT value
FROM modx_site_tmplvar_contentvalues
USE INDEX (tv_cnt)
WHERE contentid=id AND tmplvarid={$changeFreqId}
), '</changefreq>'), ''),
'</url>'
SEPARATOR ''
) AS node
FROM modx_site_content AS s
WHERE s.deleted = 0 AND s.published = 1 AND s.searchable = 1 AND context_key='web'
GROUP BY s.id
ORDER BY s.id ASC
");
if ($stmt) {
$rows = $stmt->fetchAll(PDO::FETCH_COLUMN);
$output .= implode('', $rows);
}
$output .= '</urlset>';
$modx->cacheManager->set('sitemap', $output, 86400, $options);
}
return $output;`
Как вы видите, запрос установлен для получения приоритета и частоты изменений из двух ТВ - это схоже на то, как дополнения для генерации карты сайта способны устанавливать пользовательские приоритеты и частоту изменений для ресурса. Если значения не установлены специально для ресурса, он не выводит соответствующую часть ноды и будет использовать значения для Гугла по-умолчанию.
Отмечу в частности USE INDEX(tv_cnt) в подзапросах: он сообщает подзапросам использовать специальный индех привязанный к фильтрации ИД ТВ и ИД контента - без этого запрос занимал бы значительное время.
Также ещё пару вещей нужно отметить:
- Запрос ограничен ресурсами в web контексте. Если вы решите использовать этот сниппет для другого контекса, помните, что нужно обновить ключ контекста
- Вывод закеширован на 24 часа. Если нужно другое время хранения в кеше - поменяйте значение 86400 на нужное вам в секундах
- Можете свободно менять скрипт для ваших нужд и давайте ваши отзывы.
Оригинал статьи Generating a Google Sitemap when you have thousands of resources