php - Joomla 3.x 中的 MySQL 查询慢得离谱

标签 php mysql optimization joomla joomla3.1

在我继续之前,我只想说,当你用谷歌搜索“slow joomla”或“optimize joomla”时,我已经做了所有推荐的事情。也就是说,我的网站是 GZipped,我所有的 css 和 js 都经过优化和缩小,我没有运行任何不必要的组件、插件或模块(实际上几乎没有),我的图像经过优化,缓存已打开(页面和 Progressive),我在 Rackspace 的 supah-fast 云托管上,我的 SQL 数据库在单独的 Rackspace 服务器上。

所有这一切,我仍然得到 10-12 秒以上的加载时间,有时多达 14-15 秒。

从 Joomla 调试:

Application 0.000 seconds (+0.000); 0.75 MB (+0.755) - afterLoad
Application 0.027 seconds (+0.027); 2.25 MB (+1.491) - afterInitialise
Application 0.040 seconds (+0.013); 3.26 MB (+1.010) - afterRoute
Application 11.986 seconds (+11.947); 5.09 MB (+1.833) - afterDispatch
Application 12.000 seconds (+0.014); 5.63 MB (+0.539) - beforeRenderModule mod_chronoforms (Tip Line)
Application 12.006 seconds (+0.005); 5.85 MB (+0.225) - afterRenderModule mod_chronoforms (Tip Line)
Application 12.008 seconds (+0.002); 5.86 MB (+0.006) - beforeRenderModule mod_custom_advanced (Sponsors)
Application 12.009 seconds (+0.002); 5.88 MB (+0.019) - afterRenderModule mod_custom_advanced (Sponsors)
Application 12.010 seconds (+0.001); 5.87 MB (-0.006) - beforeRenderModule mod_flexi_customcode (Popular Now)
Application 12.012 seconds (+0.002); 5.89 MB (+0.018) - afterRenderModule mod_flexi_customcode (Popular Now)
Application 12.012 seconds (+0.001); 5.84 MB (-0.046) - beforeRenderModule mod_articles_category (Featured Articles)
Application 12.033 seconds (+0.021); 5.97 MB (+0.127) - afterRenderModule mod_articles_category (Featured Articles)
Application 12.033 seconds (+0.000); 5.96 MB (-0.014) - beforeRenderModule mod_search (Search)
Application 12.036 seconds (+0.002); 5.98 MB (+0.022) - afterRenderModule mod_search (Search)
Application 12.036 seconds (+0.001); 5.93 MB (-0.050) - beforeRenderModule mod_acymailing (AcyMailing Module)
Application 12.044 seconds (+0.007); 6.44 MB (+0.507) - afterRenderModule mod_acymailing (AcyMailing Module)
Application 12.157 seconds (+0.114); 6.72 MB (+0.289) - afterRender

afterDispatch 的 (+11.947) 提示我这可能是 MySQL 查询的问题,所以我开始通过 PHPMyAdmin 运行一些长(长,长)查询。

我发现诸如此类的查询(第一个为类别博客 View 加载 8 篇文章——据我所知,第二个执行相同的搜索,减去 LIMIT,允许分页)每个页面需要 2 到 3 秒才能完成,并且每次加载页面时都会有 40 多个查询(尽管绝大多数都没有那么笨拙):

SELECT a.id, a.title, a.alias, a.introtext, 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, 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,contact.id as contactid,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 mydatabase_content AS a 
  LEFT JOIN mydatabase_content_frontpage AS fp 
  ON fp.content_id = a.id 
  LEFT JOIN mydatabase_categories AS c 
  ON c.id = a.catid 
  LEFT JOIN mydatabase_users AS ua 
  ON ua.id = a.created_by 
  LEFT JOIN mydatabase_users AS uam 
  ON uam.id = a.modified_by 
  LEFT JOIN ( SELECT contact.user_id, MAX(contact.id) AS id, contact.language 
  FROM mydatabase_contact_details AS contact 
  WHERE contact.published = 1 
  GROUP BY contact.user_id, contact.language) AS contact 
  ON contact.user_id = a.created_by 
  LEFT JOIN mydatabase_categories as parent 
  ON parent.id = c.parent_id 
  LEFT JOIN mydatabase_content_rating AS v 
  ON a.id = v.content_id 
  LEFT 
  OUTER JOIN (SELECT cat.id as id 
  FROM mydatabase_categories AS cat JOIN mydatabase_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,5) 
  AND c.access IN (1,1,5) 
  AND 
  CASE WHEN badcats.id is null THEN a.state ELSE 0 END = 1 
  AND (a.catid = 164 OR a.catid IN ( SELECT sub.id 
  FROM mydatabase_categories as sub 
  INNER JOIN mydatabase_categories as this 
  ON sub.lft > this.lft 
  AND sub.rgt < this.rgt 
  WHERE this.id = 164)) 
  AND (a.publish_up = '0000-00-00 00:00:00' OR a.publish_up <= '2013-08-07 07:00:01') 
  AND (a.publish_down = '0000-00-00 00:00:00' OR a.publish_down >= '2013-08-07 07:00:01') 
  GROUP BY a.id, a.title, a.alias, a.introtext, a.checked_out, a.checked_out_time, a.catid, a.created, a.created_by, a.created_by_alias, a.created, a.modified, a.modified_by, uam.name, a.publish_up, a.attribs, a.metadata, a.metakey, a.metadesc, a.access, a.hits, a.xreference, a.featured, a.fulltext, a.state, a.publish_down, badcats.id, c.title, c.path, c.access, c.alias, uam.id, ua.name, ua.email, contact.id, parent.title, parent.id, parent.path, parent.alias, v.rating_sum, v.rating_count, c.published, c.lft, a.ordering, parent.lft, fp.ordering, c.id, a.images, a.urls 
  ORDER BY 
  CASE WHEN a.publish_up = '0000-00-00 00:00:00' THEN a.created ELSE a.publish_up END DESC , a.created 
LIMIT 0, 7

---

SELECT a.id, a.title, a.alias, a.introtext, 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, 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,contact.id as contactid,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 mydatabase_content AS a 
  LEFT JOIN mydatabase_content_frontpage AS fp 
  ON fp.content_id = a.id 
  LEFT JOIN mydatabase_categories AS c 
  ON c.id = a.catid 
  LEFT JOIN mydatabase_users AS ua 
  ON ua.id = a.created_by 
  LEFT JOIN mydatabase_users AS uam 
  ON uam.id = a.modified_by 
  LEFT JOIN ( SELECT contact.user_id, MAX(contact.id) AS id, contact.language 
  FROM mydatabase_contact_details AS contact 
  WHERE contact.published = 1 
  GROUP BY contact.user_id, contact.language) AS contact 
  ON contact.user_id = a.created_by 
  LEFT JOIN mydatabase_categories as parent 
  ON parent.id = c.parent_id 
  LEFT JOIN mydatabase_content_rating AS v 
  ON a.id = v.content_id 
  LEFT 
  OUTER JOIN (SELECT cat.id as id 
  FROM mydatabase_categories AS cat JOIN mydatabase_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,5) 
  AND c.access IN (1,1,5) 
  AND 
  CASE WHEN badcats.id is null THEN a.state ELSE 0 END = 1 
  AND (a.catid = 164 OR a.catid IN ( SELECT sub.id 
  FROM mydatabase_categories as sub 
  INNER JOIN mydatabase_categories as this 
  ON sub.lft > this.lft 
  AND sub.rgt < this.rgt 
  WHERE this.id = 164)) 
  AND (a.publish_up = '0000-00-00 00:00:00' OR a.publish_up <= '2013-08-07 07:00:01') 
  AND (a.publish_down = '0000-00-00 00:00:00' OR a.publish_down >= '2013-08-07 07:00:01') 
  GROUP BY a.id, a.title, a.alias, a.introtext, a.checked_out, a.checked_out_time, a.catid, a.created, a.created_by, a.created_by_alias, a.created, a.modified, a.modified_by, uam.name, a.publish_up, a.attribs, a.metadata, a.metakey, a.metadesc, a.access, a.hits, a.xreference, a.featured, a.fulltext, a.state, a.publish_down, badcats.id, c.title, c.path, c.access, c.alias, uam.id, ua.name, ua.email, contact.id, parent.title, parent.id, parent.path, parent.alias, v.rating_sum, v.rating_count, c.published, c.lft, a.ordering, parent.lft, fp.ordering, c.id, a.images, a.urls 
  ORDER BY 
  CASE WHEN a.publish_up = '0000-00-00 00:00:00' THEN a.created ELSE a.publish_up END DESC , a.created

编辑

这是第一个查询的 EXPLAIN:

EXPLAIN query 1

第二个:

EXPAIN query 2

我的 _content 表有 14,000 多行,我知道这在宏伟的计划中并不算多。

/编辑

有没有人找到优化这个的好方法?我不反对破解核心(我知道他们不反对,但如果你不能进入并摆弄它,那么开源项目的意义何在?)如果那是它所需要的。

编辑 2 - 已解决(某种程度上)。

所以,我找到了this guy谁似乎走上了正确的道路,所以我说见鬼去吧,然后试了一下。

在 components/com_content/models/articles.php 中,我替换了 line 431

$query->where('(a.publish_up = ' . $nullDate . ' OR a.publish_up <= ' . $nowDate . ')')
                ->where('(a.publish_down = ' . $nullDate . ' OR a.publish_down >= ' . $nowDate . ')');

$query->where('(a.publish_up >= DATE_SUB(NOW(), INTERVAL 1 YEAR))');

我知道这对每个人都不起作用,因为它可能会破坏分页,但到目前为止它似乎对我有用(我的模板使用 js 无限滚动解决方案而不是分页)。我想如果有人要查找超过一年的文章,他们可以使用搜索功能。

这两个查询现在每个都需要不到 0.04 秒的时间来完成,Joomla Debug 的 afterDispatch 时间减少到 1.469 秒——不是最佳的,但我可以接受并继续减少这个数字。

我知道这个解决方案很老套,可能对其他任何人都不起作用,所以我很想听听更多关于改进/优化 Joomla 核心和 Joomla 股票查询的想法。

非常感谢!

/编辑2

最佳答案

正如我已经在这里发布的那样:JOOMLA site too slow

我取消了注释

bind-address="127.0.0.1"

在 MySQL 配置文件 (my.ini) 中设置。

这提高了我在 Windows 8.1 上的本地 Joomla 安装的执行速度。

关于php - Joomla 3.x 中的 MySQL 查询慢得离谱,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18104862/

相关文章:

c++ - 在函数定义中有条件地执行计算的最佳方法

php - 在日期之间搜索 YII

php - 删除在 joomla 中不起作用的行

javascript - 如何隐藏每条记录的按钮

Mysql查询效率

python - 如何在for循环中迭代不同的值?

php - 进行多种语言的翻译

php - 如何在新标签/窗口中打开每个 Wordpress 帖子?

mysql - Mamp - MySql 无法启动

javascript - 使用 RequireJS 优化后需要优化的模块