SQL Query优化避免临时表

时间:2012-08-10 06:00:31

标签: mysql 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

问题:

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

2 个答案:

答案 0 :(得分:11)

MySQL documentation说:

  

可以在以下条件下创建临时表:

     

如果有ORDER BY子句和不同的GROUP BY子句,   或者如果ORDER BYGROUP BY包含除了表之外的列   在连接队列中的第一个表中,创建了一个临时表。

因此,您只能通过删除order by Created

来避免使用临时表

答案 1 :(得分:4)

正如您可能理解的那样,问题是GROUP BYUserId订购数据,但结果集应按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