Производительность Joomla на больших объемах контента

Тема в разделе "Joomla", создана пользователем pasha-b, 30 апр 2018.

  1. pasha-b

    pasha-b

    Регистрация:
    9 янв 2013
    Сообщения:
    166
    Симпатии:
    75
    На Хабре появилась такая статья. Кому интересно, может перейти по ссылке, для остальных размещаю ее здесь, может кому-то поможет.

    Joomla очень плохо переваривает базу данных даже с несколькими тысячами статей в таблице _content. При нескольких десятках тысяч запросы в базу стандартных модулей типа mod_articles_popular могут зависать на секунды ( в комментариях к статье написали, что 5 000 статей для Joomla!, это ерунда, проблемы могут возникнуть, когда статей более 20 000, поэтому оставим это утверждение на совести автора статьи).
    Всё дело в ACL (Access Control List) — политике контроля доступа. Проверка законности доступа пользователя к материалам занимает свыше 98% времени выполнения запроса.
    Тем временем, есть сайты, которым это не нужно. Например, новостной сайт, показывающий в левой колонке модуль «Самые читаемые статьи» всем подряд. Что делать в этом случае? Отключить проверку ACL в helper.php модуля. Благо это не трудно — просто комментируем строку:
    Код:
    $model->setState('filter.access', $access);
    Давайте посмотрим на результат. Включаем в админке отладку, смотрим в дебаг-информации запрос в базу данных этого модуля. Вот он без ACL:
    Код:
    Время запроса: 18.84 ms После последнего запроса: 6.38 ms Память запроса: 0.012 MB Память до запроса: 7.288 MB Выбрано строк: 5
    
    SELECT a.id, a.title, a.alias, a.introtext, a.fulltext, a.checked_out, a.checked_out_time, a.catid, a.created, a.created_by, a.created_by_alias,
      CASE WHEN a.modified = '0000-00-00 00:00:00' THEN a.created ELSE a.modified END as modified, a.modified_by, uam.name as modified_by_name,
      CASE WHEN a.publish_up = '0000-00-00 00:00:00' THEN a.created ELSE a.publish_up END as publish_up,a.publish_down, a.images, a.urls, a.attribs, a.metadata, a.metakey, a.metadesc, a.access, a.hits, a.xreference, a.featured, a.language,  LENGTH(a.fulltext) AS readmore,
      CASE WHEN badcats.id is not null THEN 0 ELSE a.state END AS state,c.title AS category_title, c.path AS category_route, c.access AS category_access, c.alias AS category_alias,
      CASE WHEN a.created_by_alias > ' ' THEN a.created_by_alias ELSE ua.name END AS author,ua.email AS author_email,parent.title as parent_title, parent.id as parent_id, parent.path as parent_route, parent.alias as parent_alias,ROUND(v.rating_sum / v.rating_count, 0) AS rating, v.rating_count as rating_count,c.published,
      CASE WHEN badcats.id is null THEN c.published ELSE 0 END AS parents_published
    
      FROM jos_content AS a
    
      LEFT JOIN jos_categories AS c
      ON c.id = a.catid
    
      LEFT JOIN jos_users AS ua
      ON ua.id = a.created_by
    
      LEFT JOIN jos_users AS uam
      ON uam.id = a.modified_by
    
      LEFT JOIN jos_categories as parent
      ON parent.id = c.parent_id
    
      LEFT JOIN jos_content_rating AS v
      ON a.id = v.content_id
    
      LEFT
      OUTER JOIN (SELECT cat.id as id
      FROM jos_categories AS cat JOIN jos_categories AS parent
      ON cat.lft BETWEEN parent.lft
      AND parent.rgt
      WHERE parent.extension = 'com_content'
      AND parent.published != 1
      GROUP BY cat.id ) AS badcats
      ON badcats.id = c.id
    
      WHERE
    
    
      CASE WHEN badcats.id is null THEN a.state ELSE 0 END = 1
      AND a.catid IN (9,11,12,13,15,21,24,25)
      AND a.publish_up >= DATE_SUB('2018-04-30 03:27:24', INTERVAL 60 DAY)
    
      ORDER BY a.hits DESC
      LIMIT 5
    Вот с ACL:
    Код:
    Время запроса: 972.79 ms После последнего запроса: 3.96 ms Память запроса: 0.012 MB Память до запроса: 7.378 MB Выбрано строк: 5
    
    SELECT a.id, a.title, a.alias, a.introtext, a.fulltext, a.checked_out, a.checked_out_time, a.catid, a.created, a.created_by, a.created_by_alias,
      CASE WHEN a.modified = '0000-00-00 00:00:00' THEN a.created ELSE a.modified END as modified, a.modified_by, uam.name as modified_by_name,
      CASE WHEN a.publish_up = '0000-00-00 00:00:00' THEN a.created ELSE a.publish_up END as publish_up,a.publish_down, a.images, a.urls, a.attribs, a.metadata, a.metakey, a.metadesc, a.access, a.hits, a.xreference, a.featured, a.language,  LENGTH(a.fulltext) AS readmore,
      CASE WHEN badcats.id is not null THEN 0 ELSE a.state END AS state,c.title AS category_title, c.path AS category_route, c.access AS category_access, c.alias AS category_alias,
      CASE WHEN a.created_by_alias > ' ' THEN a.created_by_alias ELSE ua.name END AS author,ua.email AS author_email,parent.title as parent_title, parent.id as parent_id, parent.path as parent_route, parent.alias as parent_alias,ROUND(v.rating_sum / v.rating_count, 0) AS rating, v.rating_count as rating_count,c.published,
      CASE WHEN badcats.id is null THEN c.published ELSE 0 END AS parents_published
    
      FROM jos_content AS a
    
      LEFT JOIN jos_categories AS c
      ON c.id = a.catid
    
      LEFT JOIN jos_users AS ua
      ON ua.id = a.created_by
    
      LEFT JOIN jos_users AS uam
      ON uam.id = a.modified_by
    
      LEFT JOIN jos_categories as parent
      ON parent.id = c.parent_id
    
      LEFT JOIN jos_content_rating AS v
      ON a.id = v.content_id
    
      LEFT
      OUTER JOIN (SELECT cat.id as id
      FROM jos_categories AS cat JOIN jos_categories AS parent
      ON cat.lft BETWEEN parent.lft
      AND parent.rgt
      WHERE parent.extension = 'com_content'
      AND parent.published != 1
      GROUP BY cat.id ) AS badcats
      ON badcats.id = c.id
    
      WHERE a.access IN (1,1,2,3,6)
      AND c.access IN (1,1,2,3,6)
      AND
      CASE WHEN badcats.id is null THEN a.state ELSE 0 END = 1
      AND a.catid IN (9,11,12,13,15,21,24,25)
      AND a.publish_up >= DATE_SUB('2018-04-30 03:36:50', INTERVAL 60 DAY)
    
      ORDER BY a.hits DESC
      LIMIT 5
    Разница всего в двух проверках в WHERE клаузе:
    Код:
    a.access IN (1,1,2,3,6)  AND c.access IN (1,1,2,3,6)
    а также во времени выполнения запроса в первой строке: 19 миллисекунд и 973 миллисекунды. 98%. На базе данных с 5000 статей. На мощном сервере хостера. Это цена широко разрекламированного Joomla ACL.
    Но, оказывается, разработчики этого фреймворка прекрасно в курсе данного момента, и встроили в ее админку возможность отключить проверку ACL. Но сделали это так, чтобы никто не догадался.
    Опция находится в «Общие настройки» -> «Материалы», внизу первого таба «Материалы», называется «Показывать ссылки неавторизованным». Расшифровывается всплывающей подсказкой как: "Если установлено значение Да, то ссылки на просмотр полного текста материалов смогут видеть все пользователи, в том числе, не прошедшие авторизацию, но для просмотра полного текста система потребует ввести логин и пароль".
    Вроде бы к делу не относится, но выполняет именно то, что надо — отменяет проверку ACL для всех модулей (которые используют эту политику). Переменная $access в $model->setState('filter.access', $access) — это именно этот чекбокс (с обратным/восклицательным знаком). О его существовании подсказал один из разработчиков этого CMS-а.
    Кому нужно, могут оживить свою Джумлу.
     
    Zulus и $iD нравится это.