2012-08-10 62 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