2016-03-10 121 views
1

mysql-5.6.24-win32.1432006610MySQL:爲什麼在使用索引時仍然會'使用filesort'?

我有兩個用戶消息表。

TMessageBody (id, body)存儲消息的正文。

TMessage (id, uid, folderId, msgBodyId, subject) 存儲用戶在文件夾中的用戶郵件,如收件箱,發件箱。


創建表的SQL

create table TMessageBody (
    id   int unsigned not null primary key auto_increment, 
    body  text   not null 
); 


create table TMessage (
    id   int unsigned not null primary key auto_increment, 
    uid   int unsigned not null, 
    folderId int unsigned not null, 
    msgBodyId int unsigned not null, 
    subject  varchar(256) not null 
); 

一些測試數據

insert into TMessageBody 
    (body) values 
    ('Here is body 1') 
    ,('Here is body 2') 
    ,('Here is body 3') 
    ,('Here is body 4') 
    ,('Here is body 5') 
    ,('Here is body 6') 
    ,('Here is body 7') 
    ,('Here is body 8') 
    ,('Here is body 9') 
    ; 

insert into TMessage 
    (uid, folderId, msgBodyId, subject) values 
    (1, 999, 1, 'Hello jack') 
    , (1, 999, 2, 'Jack, how are you') 
    , (1, 888, 3, 'Good morning jack') 
    , (2, 888, 4, 'I love you, rose') 
    , (2, 999, 5, 'I love you, rose') 
    , (3, 888, 6, 'Peter, please call back') 
    , (3, 999, 7, 'What are you doing, Peter') 
    , (3, 999, 8, 'Happy birthday, perter') 
    , (4, 999, 9, 'Let me know if you are ready') 
    ; 

索引

create index Idx_MsgBodyId  on TMessage(msgBodyId); 
create index Idx_Uid_FolderId on TMessage(uid, folderId); 

1.FileSort示出了當folderId不在WHERE子句

的下面查詢由給定用戶ID獲取包括消息體的所有消息:

SET @uid=3; 
SET @folderId=999; 

EXPLAIN 
SELECT * 
FROM  TMessage 
INNER JOIN TMessageBody 
ON   TMessage.msgBodyId=TMessageBody.id 
WHERE  [email protected] 
       #AND [email protected] 
ORDER BY TMessage.id DESC 
; 

說明結果是:

mysql> EXPLAIN 
-> SELECT * 
-> FROM   TMessage 
-> INNER JOIN  TMessageBody 
-> ON    TMessage.msgBodyId=TMessageBody.id 
-> WHERE   [email protected] 
->      #AND [email protected] 
-> ORDER BY  TMessage.id DESC 
-> ; 
+----+-------------+--------------+--------+--------------------------------+------------------+---------+-------------------------+------+-----------------------------+ 
| id | select_type | table  | type | possible_keys     | key    | key_len | ref      | rows | Extra      | 
+----+-------------+--------------+--------+--------------------------------+------------------+---------+-------------------------+------+-----------------------------+ 
| 1 | SIMPLE  | TMessage  | ref | Idx_MsgBodyId,Idx_Uid_FolderId | Idx_Uid_FolderId | 4  | const     | 3 | Using where; Using filesort | 
| 1 | SIMPLE  | TMessageBody | eq_ref | PRIMARY      | PRIMARY   | 4  | test.TMessage.msgBodyId | 1 | NULL      | 
+----+-------------+--------------+--------+--------------------------------+------------------+---------+-------------------------+------+-----------------------------+ 
2 rows in set (0.00 sec) 

2.FileSort消失時folderId是在WHERE子句

該查詢是與上述一個除了WHERE子句爲相同:

SET @uid=3; 
SET @folderId=999; 

EXPLAIN 
SELECT * 
FROM  TMessage 
INNER JOIN TMessageBody 
ON   TMessage.msgBodyId=TMessageBody.id 
WHERE  [email protected] 
        AND [email protected] 
ORDER BY TMessage.id DESC 
; 

的EXPLAIN結果是:

mysql> EXPLAIN 
-> SELECT * 
-> FROM   TMessage 
-> INNER JOIN  TMessageBody 
-> ON    TMessage.msgBodyId=TMessageBody.id 
-> WHERE   [email protected] 
->       AND [email protected] 
-> ORDER BY  TMessage.id DESC 
-> ; 
+----+-------------+--------------+--------+--------------------------------+------------------+---------+-------------------------+------+-------------+ 
| id | select_type | table  | type | possible_keys     | key    | key_len | ref      | rows | Extra  | 
+----+-------------+--------------+--------+--------------------------------+------------------+---------+-------------------------+------+-------------+ 
| 1 | SIMPLE  | TMessage  | ref | Idx_MsgBodyId,Idx_Uid_FolderId | Idx_Uid_FolderId | 8  | const,const    | 2 | Using where | 
| 1 | SIMPLE  | TMessageBody | eq_ref | PRIMARY      | PRIMARY   | 4  | test.TMessage.msgBodyId | 1 | NULL  | 
+----+-------------+--------------+--------+--------------------------------+------------------+---------+-------------------------+------+-------------+ 
2 rows in set (0.00 sec) 

問題

兩個查詢之間的區別是folderId列是否WHERE子句。根據EXPLAIN結果,這兩個查詢都使用Idx_Uid_FolderId索引。我想知道爲什麼一個顯示FileSort,但其他沒有。


更新

試圖在第一次查詢中使用ORDER BY TMessage.folderId, TMessage.id DESC。但Using filesort仍然存在於EXPLAIN結果中。

mysql> EXPLAIN 
-> SELECT * 
-> FROM  TMessage 
-> INNER JOIN TMessageBody 
-> ON   TMessage.msgBodyId=TMessageBody.id 
-> WHERE  [email protected] 
->     #AND [email protected] 
-> ORDER BY TMessage.folderId, TMessage.id DESC 
-> ; 
+----+-------------+--------------+--------+--------------------------------+------------------+---------+-------------------------+------+-----------------------------+ 
| id | select_type | table  | type | possible_keys     | key    | key_len | ref      | rows | Extra      | 
+----+-------------+--------------+--------+--------------------------------+------------------+---------+-------------------------+------+-----------------------------+ 
| 1 | SIMPLE  | TMessage  | ref | Idx_MsgBodyId,Idx_Uid_FolderId | Idx_Uid_FolderId | 4  | const     | 3 | Using where; Using filesort | 
| 1 | SIMPLE  | TMessageBody | eq_ref | PRIMARY      | PRIMARY   | 4  | test.TMessage.msgBodyId | 1 | NULL      | 
+----+-------------+--------------+--------+--------------------------------+------------------+---------+-------------------------+------+-----------------------------+ 
2 rows in set (0.06 sec) 

回答

2

將索引想象爲級聯值。

在這種情況下,你的指數是

uid | folderId | id 

ID是最後的,因爲它是你的第二個索引到主鍵的參考。

在第一種情況下,您按照uid篩選,然後按ID排序。問題是,MySQL不能假定id是按順序排序的,因爲索引實際上是由filterId命令的,然後再按id過濾。

例如:

uid | folderId | id 
    1 |  1 | 1 
    1 |  2 | 2 
    2 |  1 | 3 

因此不能被用於排序該指數,由於指數的排序比由子句的順序不同。

現在,我的問題是:你爲什麼試圖避免filesort?除非你遇到性能問題,否則使用filesort是完全沒問題的。儘管有這個名字,排序在內存中完成,除非另有說明(使用臨時)。

+0

謝謝,你很好! – Zach

+0

我試過'在第一個查詢中使用TMessage.folderId,TMessage.id DESC'命令,'使用filesort'仍然存在。正如你所說,在大多數情況下是可以接受的,但我仍然想知道爲什麼在這種情況下。 – Zach

+0

@Zach哦,我會從我的答案中刪除那一點 – ESG

相關問題