如何使用GROUP BY和ORDER BY优化查询

时间:2011-03-08 00:44:11

标签: mysql sql query-optimization

我有一个POSTS表,结构是这样的:

CREATE TABLE IF NOT EXISTS `posts` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) COLLATE utf8_turkish_ci DEFAULT NULL,
  `content` longtext COLLATE utf8_turkish_ci,
  `excerpt` longtext COLLATE utf8_turkish_ci,
  `link` longtext COLLATE utf8_turkish_ci,
  `original_link` longtext COLLATE utf8_turkish_ci,
  `mime_type` longtext COLLATE utf8_turkish_ci,
  `language_id` int(11) DEFAULT NULL,
  `user_id` int(11) DEFAULT NULL,
  `site_id` int(11) DEFAULT NULL,
  `type` varchar(255) COLLATE utf8_turkish_ci DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  `modified_at` datetime DEFAULT NULL,
  `is_deleted` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `user_id` (`user_id`),
  KEY `type` (`type`),
  KEY `created_at` (`created_at`),
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_turkish_ci AUTO_INCREMENT=52487 ;

一个USERS表,结构如下:

CREATE TABLE IF NOT EXISTS `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) COLLATE utf8_turkish_ci NOT NULL,
  PRIMARY KEY (`id`),
  KEY `username` (`username`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_turkish_ci AUTO_INCREMENT=9422 ;

我正在使用此查询来获取按照下降时间排序的最新“页面,文件或帖子”帖子,并按用户分组以显示用户的所有最新帖子:

   SELECT p.*, u.* 
     FROM posts p 
LEFT JOIN users u ON p.user_id = u.id 
    WHERE p.type IN ('post', 'page', 'file') 
 GROUP BY p.user_id 
 ORDER BY p.created_at DESC 
    LIMIT 30

但它太慢了,甚至限制在30个记录中。

现在,我怎样才能加快这个查询?要索引哪些列或任何其他想法?感谢。

4 个答案:

答案 0 :(得分:2)

要做的第一件事是在posts.user_id(或者posts.user_id + posts.type)上添加索引。以及posts.created_at

上的另一个索引

<强>更新
我只是注意你的查询从两个表中获取所有字段,而posts表有6个长文本列。所以我相信你的性能很差,因为mysql必须创建一个相当大的临时表或临时文件来获取所有行以满足你的group by + order by子句。 我认为以下查询应该有所帮助。

  SELECT u.*, p1.* FROM
  users u 
  INNER JOIN 
  (
      SELECT p.user_id, p.created_at, p.id FROM posts p 
      WHERE  p.type IN ('post', 'page', 'file')  GROUP by p.user_id 
      ORDER BY p.created_at DESC LIMIT 30
  )xxx ON xxx.user_id = u.id
   INNER JOIN posts p1 ON (p1.id = xxx.id)

答案 1 :(得分:0)

就索引而言,我建议在posts.type(WHERE),posts.created_at(ORDER)上创建一个。这应该有助于加快排序。

答案 2 :(得分:0)

你可以试试这个:

SELECT p。,u。
     FROM(SELECT * FROM帖子WHERE p.type IN(&#39; post&#39;,&#39; page&#39;,&#39; file&#39;))p
LEFT JOIN用户u on p.user_id = u.id
    GROUP BY p.user_id ORDER BY p.created_at DESC     限制30

MySQL首先处理内部查询,并使用其结果进程处理具有较少记录的outter查询。

答案 3 :(得分:0)

尝试@ Gabriel的答案,但在内部查询中使用LIMIT。

SELECT p。,u。 FROM(SELECT * FROM posts WHERE type IN('post','page','file')ORDER BY created_at DESC LIMIT 30)p LEFT JOIN用户u on p.user_id = u.id ORDER BY p.created_at;