2012-08-10 45 views
10

表:SQL查询优化,以避免临时表

CREATE TABLE `T1` (
    `UserId` int(10) unsigned NOT NULL, 
    `FriendUserId` int(10) unsigned NOT NULL, 
    `IsDisplayed` tinyint(1) unsigned NOT NULL, 
    `Created` datetime NOT NULL, 
    KEY `FriendUserId` (`FriendUserId`,`IsDisplayed`,`UserId`,`Created`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8; 

查询:

SELECT `UserId`, `FriendUserId`, UNIX_TIMESTAMP(`Created`) AS `Created` 
FROM `T1` WHERE `FriendUserId` = 22 
    AND `IsDisplayed` = 0 
    GROUP BY `UserId` 
    ORDER BY `Created` 

EXPLAIN结果:

  id: 1 
    select_type: SIMPLE 
     table: T1 
     type: ref 
possible_keys: FriendUserId 
      key: FriendUserId 
     key_len: 5 
      ref: const,const 
     rows: 1 
     Extra: Using where; Using index; Using temporary; Using filesort 

问题:

如何优化它,以便不使用临时表?

回答

3

正如你可能知道避免使用临时表的,问题是GROUP BY订单由UserId数据,但所得到的一组应该由Created订购;因此,MySQL把输出放在一个临时表中,对它进行排序并输出。

诀窍可能是一次性强制以Created的顺序输出不同的行。

第一个是在我脑海中是这样的:

SELECT DISTINCT 
    UserId, 
    FriendUserId, 
    UNIX_TIMESTAMP(`Created`) AS `Created` 
FROM T1 
WHERE FriendUserId = 22 AND IsDisplayed = 0 
ORDER BY `Created` 

和索引更改为(FriendUserId, IsDisplayed, Created, UserId)

或与同一指数的另一个查询:

SELECT 
    UserId, 
    FriendUserId, 
    UNIX_TIMESTAMP(`Created`) AS `Created` 
FROM T1 
WHERE FriendUserId = 22 AND IsDisplayed = 0 
GROUP BY `Created`, UserId 
9

的MySQL documentation说:

临时表可以如在这些条件下被创建:

如果有一个ORDER BY子句和不同GROUP BY子句, 或者如果ORDER BYGROUP BY包含列从 以外的表中加入队列中的第一个表,将创建一个临时表。

所以,你只能仅通过拆除order by Created