2011-03-08 111 views
2

我有一個POSTS表,其結構是這樣的:如何優化查詢使用GROUP BY和ORDER BY

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表,structed這樣的:

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條記錄。

現在,我該如何加快這個查詢?哪些列索引或任何其他想法?謝謝。

+0

桌子有多大? – slau 2011-03-08 00:51:24

+0

用戶表擁有超過9000個用戶,帖子表超過50,000個帖子 – cnkt 2011-03-08 00:53:11

回答

2

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

更新另一個指標
我只是祈禱,注意你的查詢抓住兩個表中的所有字段,職位表中有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

這也是我的呼叫,但OP更新了CREATE TABLE以顯示user_id已編入索引:/ – 2011-03-08 00:51:09

+0

@OMG Ponies。嗯我知道。也許'user_id + type'會很有用...... – a1ex07 2011-03-08 00:53:29

+0

是的,我爲查詢中提到的每一列創建索引,但沒有任何變化:( – cnkt 2011-03-08 01:24:50

0

在索引方面,我建議在posts.type(WHERE),posts.created_at(ORDER)上創建一個。這應該有助於加快排序。

0

您可以試試這個:

SELECT p。 ,u。
FROM(SELECT * FROM帖裏紙張類型IN( '後', '網頁', '文件'))p
LEFT JOIN用戶U ON p.user_id = u.id
GROUP BY p.user_id ORDER BY p.created_at DESC LIMIT 30

MySQL首先處理內部查詢,並用其結果處理帶有較少記錄的外部查詢。

+0

該查詢仍然需要7秒。沒有收穫。 – cnkt 2011-03-08 01:22:58

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;