优化mysql查询

时间:2018-02-13 13:51:19

标签: mysql wordpress query-optimization

我有以下mysql查询,这需要花费很长时间(40秒)才能加载结果。

SELECT SQL_CALC_FOUND_ROWS blog_posts.ID FROM blog_posts 
LEFT JOIN blog_term_relationships AS tt0 ON (blog_posts.ID = tt0.object_id) 
LEFT JOIN blog_term_relationships AS tt1 ON (blog_posts.ID = tt1.object_id) 
LEFT JOIN blog_term_relationships AS tt2 ON (blog_posts.ID = tt2.object_id) 
LEFT JOIN blog_term_relationships AS tt3 ON (blog_posts.ID = tt3.object_id) 
WHERE 1=1  
AND ( ( tt0.term_taxonomy_id IN (141,177) AND tt1.term_taxonomy_id IN (2389,2390) ) 
OR ( tt2.term_taxonomy_id IN (167,1169,1715) AND tt3.term_taxonomy_id IN (2519,2520) ) ) 
AND blog_posts.post_type = 'post' AND (blog_posts.post_status = 'publish') 
GROUP BY blog_posts.ID ORDER BY blog_posts.post_date ASC LIMIT 0, 20

有没有办法优化此查询。

修改

这与wordpress有关,此查询是从wp_query自动创建的。

表结构如下,

blog_posts表:

CREATE TABLE `blog_posts` (
  `ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `post_author` bigint(20) unsigned NOT NULL DEFAULT '0',
  `post_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `post_date_gmt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `post_content` longtext NOT NULL,
  `post_title` text NOT NULL,
  `post_excerpt` text NOT NULL,
  `post_status` varchar(20) NOT NULL DEFAULT 'publish',
  `comment_status` varchar(20) NOT NULL DEFAULT 'open',
  `ping_status` varchar(20) NOT NULL DEFAULT 'open',
  `post_password` varchar(255) NOT NULL DEFAULT '',
  `post_name` varchar(200) NOT NULL DEFAULT '',
  `to_ping` text NOT NULL,
  `pinged` text NOT NULL,
  `post_modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `post_modified_gmt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `post_content_filtered` longtext NOT NULL,
  `post_parent` bigint(20) unsigned NOT NULL DEFAULT '0',
  `guid` varchar(255) NOT NULL DEFAULT '',
  `menu_order` int(11) NOT NULL DEFAULT '0',
  `post_type` varchar(20) NOT NULL DEFAULT 'post',
  `post_mime_type` varchar(100) NOT NULL DEFAULT '',
  `comment_count` bigint(20) NOT NULL DEFAULT '0',
  PRIMARY KEY (`ID`),
  KEY `type_status_date` (`post_type`,`post_status`,`post_date`,`ID`),
  KEY `post_parent` (`post_parent`),
  KEY `post_author` (`post_author`),
  KEY `post_name` (`post_name`(191))
) ENGINE=MyISAM AUTO_INCREMENT=125636 DEFAULT CHARSET=utf8

blog_term_relationships表:

CREATE TABLE `blog_term_relationships` (
  `object_id` bigint(20) unsigned NOT NULL DEFAULT '0',
  `term_taxonomy_id` bigint(20) unsigned NOT NULL DEFAULT '0',
  `term_order` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`object_id`,`term_taxonomy_id`),
  KEY `term_taxonomy_id` (`term_taxonomy_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8

EXPLAIN QUERY:

enter image description here

1 个答案:

答案 0 :(得分:2)

<强>重新配制

SELECT  SQL_CALC_FOUND_ROWS blog_posts.ID
    FROM  ( 
            (
                SELECT  object_id
                    FROM  blog_term_relationships AS tt0
                    JOIN  blog_term_relationships AS tt1 USING(object_id)
                    WHERE  tt0.term_taxonomy_id IN (141,177)
                      AND  tt1.term_taxonomy_id IN (2389,2390)

            )
        UNION DISTINCT
            (
                SELECT  object_id
                    FROM  blog_term_relationships AS tt2
                    JOIN  blog_term_relationships AS tt3 USING(object_id)
                    WHERE  tt2.term_taxonomy_id IN (167,1169,1715)
                      AND  tt3.term_taxonomy_id IN (2519,2520) ) 
          ) AS tt
    JOIN  blog_posts  ON blog_posts.ID = tt.object_id
    WHERE  blog_posts.post_type = 'post'
      AND  blog_posts.post_status = 'publish'
    ORDER BY  blog_posts.post_date ASC
    LIMIT  0, 20 

这摆脱了GROUP BY并做了其他一些事情来加速查询。

前缀索引

`post_name` varchar(200) NOT NULL DEFAULT '',
KEY `post_name` (`post_name`(191))
) ENGINE=MyISAM AUTO_INCREMENT=125636 DEFAULT CHARSET=utf8

下定决心 - 191用于版本5.6,带有utf8mb4(你没有指定); 191是如此接近200,你也可以VARCHAR(191)。删除前缀索引可能会加快您的一些查询速度。

<强> InnoDB的

不要使用MyISAM,转移到InnoDB。这就是性能,稳健性等。这恰好会导致KEY term_taxonomy_id)中的低效率。

<强> SQL_CALC_FOUND_ROWS

SQL_CALC_FOUND_ROWS成本很高。它的目的是过去。