开发者

How to Optimize a Query With GROUP BY and ORDER BY

开发者 https://www.devze.com 2023-02-15 04:59 出处:网络
I have got a POSTS table, the structure is like this: CREATE TABLE IF NOT EXISTS `posts` ( `id` int(11) NOT NULL AUTO_INCREMENT,

I have got a POSTS table, the structure is like this:

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 ;

And a USERS table, structed like this:

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 ;

I'm开发者_JS百科 using this query to get latest "page, file or post" posts ordered by descending time and grouping by user to not show all latest posts from a user:

   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

But it is too slow, even limited to 30 records.

now, how can i speed up this query? which columns to index or any other ideas? thanks.


The first thing to do is to add an index on posts.user_id (or maybe posts.user_id + posts.type). And another index on posts.created_at

UPDATE
I've just payed attention that your query grabs all fields from both tables, and posts table has 6 long text columns. So I believe you have a poor performance because mysql has to create quite a large temporary table or temp file to get all rows for satisfying your group by + order by clauses. I think the following query should help.

  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)


In terms of indices, I would suggest creating ones on posts.type (WHERE), posts.created_at (ORDER). That should help speed up the sorting.


You can try this:

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

MySQL first proccess the inner query, and with its result process the outter query with less records.


Try @Gabriel's answer, but with the LIMIT in the inner query.

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

0

精彩评论

暂无评论...
验证码 换一张
取 消