如何使这个mysql查询更有效?

时间:2014-05-28 18:13:13

标签: mysql join many-to-many

我有一个类别,帖子和M2M表category_post表。这是他们的架构

CREATE TABLE IF NOT EXISTS `posts` (
  `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
  `title` char(255) COLLATE utf8_unicode_ci NOT NULL,
  `img_url` char(255) CHARACTER SET latin1 NOT NULL,
  `content` text COLLATE utf8_unicode_ci NOT NULL,
  `pub_date` int(10) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `pub_date` (`pub_date`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=42166 ;

-- --------------------------------------------------------

CREATE TABLE IF NOT EXISTS `category` (
  `c_id` tinyint(3) unsigned NOT NULL AUTO_INCREMENT,
  `c_name` char(255) CHARACTER SET latin1 NOT NULL,
  `c_slug` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `c_active` tinyint(1) NOT NULL,
  PRIMARY KEY (`c_id`),
  KEY `c_slug` (`c_slug`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='List of Categories' AUTO_INCREMENT=47 ;

-- --------------------------------------------------------

CREATE TABLE IF NOT EXISTS `category_post` (
  `cp_id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
  `category_id` tinyint(3) unsigned NOT NULL,
  `post_id` mediumint(8) unsigned NOT NULL,
  PRIMARY KEY (`cp_id`),
  KEY `category_id` (`category_id`),
  KEY `post_id` (`post_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=60909 ;

这是一个示例查询。通常需要大约0.60秒,负载高达3秒。

SELECT * 
FROM posts p
INNER JOIN category_post cp ON p.id = cp.post_id
WHERE cp.category_id IN ( 10, 11, 12, 13, 15, 19, 33, 37, 46 ) 
GROUP BY id
ORDER BY pub_date DESC 
LIMIT 25690 , 10

说明: Explain

我一直在阅读很多参考资料和SO帖子,并对如何解决这个问题感到困惑。我很欣赏任何朝着正确方向的点头!

我发现如果我不包含“ORDER BY pub_date DESC”,则查询会在很短的时间内执行。但是pub_date是一个索引。我在某处读到mysql每个查询只使用一个索引。这就是为什么它很慢?

2 个答案:

答案 0 :(得分:1)

我看到决策上下文中使用的任何字段(wherejoin)都有一个索引。

我认为您应该将SELECT *替换为SELECT to-be-used-column

因为太多列会减慢速度。但这不是基本问题。

希望它能为你带来希望。

答案 1 :(得分:0)

解决方案是执行后期行查找。 More information here。将执行时间从600毫秒减少到90毫秒

这是更新的查询:

SELECT p.* 
FROM (
SELECT id
FROM posts temp
INNER JOIN category_post cp ON temp.id = cp.post_id
WHERE cp.category_id IN ( 10, 11, 12, 13, 15, 19, 33, 37, 46 ) 
GROUP BY id
ORDER BY pub_date ASC 
LIMIT 25690 , 10
) id_array
JOIN posts p ON p.id = id_array.id
ORDER BY p.pub_date ASC

谢谢大家的建议:)