Joomla 3.x中的MySQL查询非常慢

时间:2013-08-07 13:35:30

标签: php mysql optimization joomla joomla3.1

在进一步说明之前,我只想说,当你谷歌“慢joomla”或“优化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运行一些长(长,长)的。

我发现像这样的查询(第一个为类别 - 博客视图加载了8篇文章 - 据我所知,第二个进行相同的搜索,减去LIMIT,以允许每次加载时,需要2到3秒的EACH才能完成,并且每次加载页面时都会有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多行,我知道在宏观方案中并不是那么多。

/ EDIT

有没有人找到优化这种方法的好方法?我并不反对攻击核心(我知道他们不会这样做,但是如果你不能进入并摆弄它,那么开源项目的重点是什么?)如果这就是它所需要的。

编辑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秒 - 不是最佳,但是我能忍受的数字并继续减少。

我知道这个解决方案非常hacky,可能不适合其他任何人,所以我很想听到有关改进/优化Joomla核心和Joomla股票查询的更多想法。

非常感谢!

/编辑2

3 个答案:

答案 0 :(得分:1)

正如我在此处发布的那样:JOOMLA site too slow

我取消注释了

bind-address="127.0.0.1"

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

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

答案 1 :(得分:0)

联系表上的联接和生成的group_by存在问题。 这已在使用https://github.com/joomla/joomla-cms/pull/1542的master中修复,我认为它应该已包含在当前版本中。 您使用的是哪个版本的Joomla?

答案 2 :(得分:-1)

我在windwos托管php + mysql时遇到了问题。将主机设置为IP地址。

host 127.0.0.1