优化只需5秒即可执行的WordPress查询

时间:2015-05-28 作者:Ranknoodle

我有一个很大的wordpress数据库:

键表中的行:

730K wp\\U帖子
404K wp\\U术语
752K wp\\U术语关系
27K wp\\U术语分类
180万wp\\U帖子

问题是我有一个疑问that takes 5 seconds to complete 我想在添加任何缓存之前优化查询。

mysql> SELECT wp_posts.ID
 FROM wp_posts
 INNER JOIN wp_term_relationships
 ON (wp_posts.ID = wp_term_relationships.object_id)
 LEFT JOIN wp_postmeta
 ON (wp_posts.ID = wp_postmeta.post_id
 AND wp_postmeta.meta_key = \'_Original Post ID\' )
 LEFT JOIN wp_postmeta AS mt1
 ON ( wp_posts.ID = mt1.post_id )
 WHERE 1=1
 AND wp_posts.ID NOT IN (731467)
 AND ( wp_term_relationships.term_taxonomy_id IN (5) )
 AND wp_posts.post_type = \'post\'
 AND (wp_posts.post_status = \'publish\'
 OR wp_posts.post_status = \'private\')
 AND ( wp_postmeta.post_id IS NULL 
 OR ( mt1.meta_key = \'_Original Post ID\'
 AND CAST(mt1.meta_value AS CHAR) = \'deleted\' ) )
 GROUP BY wp_posts.ID
 ORDER BY  wp_posts.ID DESC
 LIMIT 0, 20;
结果如下:

+--------+
| ID     |
+--------+
| 731451 |
| 731405 |
| 731403 |
| 731397 |
| 731391 |
| 731385 |
| 731375 |
| 731363 |
| 731361 |
| 731353 |
| 731347 |
| 731345 |
| 731335 |
| 731331 |
| 731304 |
| 731300 |
| 731284 |
| 731273 |
| 731258 |
| 731254 |
+--------+
对查询进行解释会产生以下信息

+----+-------------+-----------------------+--------+------------------------------------------------------------+------------------+---------+----------------------------------------+--------+-----------------------------------------------------------+
| id | select_type | table                 | type   | possible_keys                                                 | key              | key_len | ref                                    | rows   |   Extra                                                     |
+----+-------------+-----------------------+--------+------------------------------------------------------------+------------------+---------+----------------------------------------+--------+-----------------------------------------------------------+
|  1 | SIMPLE      | wp_term_relationships | range  | PRIMARY,term_taxonomy_id                                      | term_taxonomy_id | 16      | NULL                                   | 130445 |   Using where; Using index; Using temporary; Using filesort |
|  1 | SIMPLE      | wp_posts              | eq_ref | PRIMARY,post_name,type_status_date,post_parent,post_author | PRIMARY          | 8       | mydatabase.wp_term_relationships.object_id |      1 | Using where                                               |
|  1 | SIMPLE      | wp_postmeta           | ref    | post_id,meta_key                                           | post_id          | 8       | mydatabase.wp_term_relationships.object_id |      1 | Using where                                               |
|  1 | SIMPLE      | mt1                   | ref    | post_id                                                    | post_id          | 8       | mydatabase.wp_term_relationships.object_id |      1 | Using where                                               |
+----+-------------+-----------------------+--------+------------------------------------------------------------+------------------+---------+----------------------------------------+--------+-----------------------------------------------------------+
如何优化此查询以更快地加载?我认为自定义索引是一种方式,但不确定在哪些字段上。此外,我还尝试订购结果wp\\U帖子。ID DESC,但获取执行查询的相同时间。

2 个回复
最合适的回答,由SO网友:Ranknoodle 整理而成

所以,如果我在这个项目中使用wordpress,我接下来要做的就是创建一个反向的帖子id索引。我认为这不是“正确”的答案,有些人肯定会完全不同意这种方法,但这在生产中对我有用。

我是从这里读到这篇博文的:

https://www.igvita.com/2007/08/20/pseudo-reverse-indexes-in-mysql/

正如我最近发现的,MySQL目前只支持按升序存储索引值。。。。AideRSS花了整整三周的时间才点击了300多万条索引博客,在这个过程中,我感觉到网站变得越来越慢:按条款降序的做法让我们很痛苦。在最坏的情况下,合并多个查询的联合意味着文件排序操作的性能会受到影响!

由于mysql的这一限制,以下命令;排序函数是查询中的瓶颈。

GROUP BY wp_posts.ID
ORDER BY  wp_posts.ID DESC
但是,删除这些条件后,查询将在20ms内返回,而生产过程中的平均时间为5-15秒。然而,问题是这些帖子是按从最老到最新的顺序排列的。我想要的是从最新到最旧的。

SELECT wp_posts.*
FROM wp_posts
WHERE wp_posts.ID IN( 
SELECT distinct(ID) 
FROM wp_posts  
INNER JOIN wp_term_relationships 
ON (wp_posts.ID = wp_term_relationships.object_id) 
LEFT JOIN wp_postmeta 
ON (wp_posts.ID = wp_postmeta.post_id 
AND wp_postmeta.meta_key = \'_Original Post ID\' ) 
LEFT JOIN wp_postmeta AS mt1 
ON ( wp_posts.ID = mt1.post_id ) 
WHERE wp_posts.ID NOT IN (795025) 
AND ( wp_term_relationships.term_taxonomy_id IN (1) ) 
AND wp_posts.post_type = \'post\' 
AND (wp_posts.post_status = \'publish\' 
OR wp_posts.post_status = \'private\') 
AND ( wp_postmeta.post_id IS NULL 
OR ( mt1.meta_key = \'_Original Post ID\' 
AND CAST(mt1.meta_value AS CHAR) = \'deleted\' ) ) ) limit 0, 20;
再次回到这篇文章:https://www.igvita.com/2007/08/20/pseudo-reverse-indexes-in-mysql/

根据彼得·扎伊采夫关于伪造反向索引的建议,我决定通过为索引博客文章的发布时间创建一个单独的反向时间戳来回避我们的问题。诀窍是,由于所有索引都是按升序存储的,因此需要存储将来某个日期的“倒计时”值,而不是存储发布日期。一些SQL查询可以做到这一点:

我决定在wp\\u posts表中以负数格式存储post ID,而不是将post创建日期存储为“反向”。

因此,我在wordpress数据库的mysql中向wp\\U posts表添加了一列。此新列存储整数负数。

alter table wp_posts add column reverse_post_id int;
更新当前帖子以使新列具有此反向编号:

 update wp_posts set reverse_post_id = (ID/ -1);
然后,我在此新的reverse\\u post\\u id上创建索引:

  create index reverse_post_id_index on wp_posts(post_type,post_status,reverse_post_id);
目前,我通过自定义api接口以编程方式插入帖子,因此在插入后创建反向帖子id。在通过界面插入帖子后,我将在wordpress中添加一个钩子来创建reverse\\u post\\u id。

Im还将添加一个mysql预定事件,以在某个时间间隔运行,以更新反向post\\U id为空的wp\\U post。

最终查询如下所示,在生产中运行时间不超过20 ms:

SELECT wp_posts.*
FROM wp_posts
WHERE wp_posts.ID IN( 
SELECT distinct(ID) 
FROM wp_posts **force index (reverse_post_id_index)** 
INNER JOIN wp_term_relationships 
ON (wp_posts.ID = wp_term_relationships.object_id) 
LEFT JOIN wp_postmeta 
ON (wp_posts.ID = wp_postmeta.post_id 
AND wp_postmeta.meta_key = \'_Original Post ID\' ) 
LEFT JOIN wp_postmeta AS mt1 
ON ( wp_posts.ID = mt1.post_id ) 
WHERE wp_posts.ID NOT IN (795025) 
AND ( wp_term_relationships.term_taxonomy_id IN (1) ) 
AND wp_posts.post_type = \'post\' 
AND (wp_posts.post_status = \'publish\' 
OR wp_posts.post_status = \'private\') 
AND ( wp_postmeta.post_id IS NULL 
OR ( mt1.meta_key = \'_Original Post ID\' 
AND CAST(mt1.meta_value AS CHAR) = \'deleted\' ) ) ) limit 0, 20;
注意添加了“force index (reverse_post_id_index)“这将返回从最新到最旧的描述顺序中的wp\\u posts,而不执行“order by”操作。需要注意的是,reverese\\u post\\u id不能为null。

同样,这可能不是正确的答案,但我找到的答案让它对我和我的处境都适用。

SO网友:MichaelICE

我也有同样的问题。如果不修改一些您可能不应该修改的代码(或者编写过滤器或“插入”)的话,这个问题是无法解决的。问题是SQL语句中的CAST指令。它在执行任何操作之前先对整个表进行强制转换,对于您拥有的记录量,这需要一段时间。

捕获查询,删除以下内容"AND CAST(mt1.meta_value AS CHAR) = \'deleted\'" 运行它,现在应该快得多。

编辑:(更正)将查询更改为"AND mt1.meta_value = \'deleted\'"

我不知道开发人员在添加无用的CAST时是怎么想的,MySQL没有它也可以正常工作(除了大小之外,文本与CHAR没有什么不同)。我确信,在某些边缘情况下,删除它将无法获得所需的结果,但我尚未找到一个。

Wordpress SQL X万岁)

结束

相关推荐

导入SQL数据库后实时站点不更新

我的live网站在从wamp本地服务器导入sql数据库后没有更新,直到最后一次一切都很完美,但昨晚我无法看到live在本地所做的更改。我所做的:-在本地创建页面并上载新的contat php页面和联系人模板-在前端做了一些更改(样式)-以sql格式导出数据库-更改sql中的链接(本地到live)-导入live mysql数据库-使用更改更新样式表,并通过ftp将新的联系人表单上载到live什么都没发生。只有样式更改生效,我没有看到添加了任何新菜单,也没有看到我创建的任何新页面。联系人表单不存在,我为表单创