2017-10-18 98 views
0

这里是一个丑陋的极端由我们的Web应用程序生成的查询。这是一个自定义的Web应用程序,必须读取旧版Wordpress数据库。我需要写什么索引来防止在非高性能MySQL查询中进行表分类?

SELECT SQL_NO_CACHE DISTINCT 
    p.ID, p.post_title, p.post_name, p.post_excerpt, p.post_date, p.post_date_gmt, p.comment_count, post_content, post_author 
FROM wp_posts p 
INNER JOIN wp_term_relationships AS tr ON p.ID = tr.object_id 
INNER JOIN wp_term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id 
INNER JOIN wp_terms AS t ON tt.term_id = t.term_id 
WHERE 
    tt.taxonomy = "post_tag" 
AND p.post_type = "post" 
AND p.post_password = '' 
AND p.post_status = "publish" 
ORDER BY p.post_date DESC 
LIMIT 0, 20 

为了给你这个数据库的大小的范围:

  • wp_posts具有约250k行。
  • wp_term_relationship有约。 1m行。
  • wp_term_taxonomy有约。 50k行。
  • wp_terms有大约50k行。

这里的EXPLAIN语句:

ID| SELECT_TYPE | TABLE | TYPE | POSSIBLE_KEYS        | KEY    | KEY_LEN | REF      | ROWS | EXTRA 
1 | SIMPLE  | tt | ref | PRIMARY,term_id_taxonomy,taxonomy   | taxonomy   | 130  | const      | 27149 | Using index condition; Using temporary; Using filesort 
1 | SIMPLE  | t  | eq_ref | PRIMARY         | PRIMARY   | 8  | wp_mu.tt.term_id   | 1  | Using index 
1 | SIMPLE  | tr | ref | PRIMARY,term_taxonomy_id     | term_taxonomy_id | 8  | wp_mu.tt.term_taxonomy_id | 11 | Using index 
1 | SIMPLE  | p  | eq_ref | PRIMARY,type_status_date,optimize_slow_tax | PRIMARY   | 8  | wp_mu.tr.object_id  | 1  | Using where 

据我所知道的,主要问题是,MySQL是生成一个临时表,并使用文件排序。

从我的阅读到目前为止,如果我能写出正确的查询,我们可以避免这整个崩溃。如果有必要创造一个母亲巨大的指数,我准备这样做。

我不是DBA,我不能轻松访问一个,所以我需要帮助来根据这个查询找出我应该写的东西。

  • 我是否构建了此查询中涉及的所有wp_posts列的索引?
  • 或者只是所有wp_posts列涉及WHERE子句?
  • 或者只是所有wp_posts列涉及WHERE和ORDER BY子句?如果是这样,按什么顺序?
  • 或者只是所有wp_posts列涉及WHERE和ORDER BY和JOIN子句?如果是这样,按什么顺序?
  • 以任何方式重新排序WHERE子句的顺序,还是MySQL已经优化了这个?
  • 如果我要创建一个MySQL视图,会有帮助吗?我的阅读暗示没有,但是最近的MySQL版本最近可能表现更好?
+0

MySQL Views没有帮助,因为它们不是物化视图。每次查询视图时,您都会逐字运行相同的查询。所以视图更像宏。正如Rick回答的,失去了“DISTINCT”。 –

+0

是的,我不这么认为。我想我可能希望MySQL 8.0有人认为让Views更高效,但也许MySQL用户刚​​刚接受了使用它们的训练。 – haz

+0

我很想切换到Postgresql以获得物化视图,但可悲的是,这不是我做出的决定,这意味着它永远不会发生。 – haz

回答

1

“Filesort”并不像听起来那么邪恶。还有其他问题需要解决速度问题。他们可能会删除文件。现在提供3个提示,其中每个提示可能都有帮助。

  1. wp_postmeta的多对多映射有几个低效率。架构改进概述为here。如果wp_term_taxonomy很多:很多,但不是wp_postmeta的克隆,那么请参阅提示here

  2. 添加INDEX(post_type, post_password, post_status, post_date)p可能会有很大帮助。 (很难说没有看到SHOW CREATE TABLE并知道有关数据分布的一些信息。)列的顺序可以是任意的,但post_date必须是最后一个。该索引可能会删除'filesort'。但更重要的是,它可能会通过WHEREORDER BY以兑现LIMIT。没有达到LIMIT,很多行必须收集,排序,最后LIMITed。这是涉及的行数,而不是文件夹,那就是小人。

  3. 哦,DISTINCT可能会强制tmp + filesort。这可以通过做

查询的显著重写被淘汰:

SELECT ... 
    FROM posts AS p 
    WHERE p.... 
     AND EXISTS (SELECT * FROM .. JOIN .. JOIN .. 
         WHERE tt.taxonomy = "post_tag" 
         AND p.ID = tr.object_id) 
    ORDER BY ... 
    LIMIT ... 

注意如何除posts每个表已被移动到子查询。之前,出现了“爆炸 - 爆裂”模式 - JOIN爆炸涉及的行数,然后GROUP BY(或DISTINCT)爆炸。这个表述避免了这种情况。

+0

我试过#2的各种变化,我似乎无法获得增加很多价值的索引。另一方面 – haz

+0

#3是魔法。现在我只需要弄清楚如何重写应用程序来重写查询。 – haz

+0

我在这个论坛上花费了很多精力,向人们展示了如何在SQL中提高效率,以便发现第三方软件受到阻碍。 :('JOIN'可能会妨碍在#2中使用'INDEX',您能否提供'EXPLAIN SELECT ...'(在添加索引后);也许我可以找到一种解决方法。 –