2016-03-10 89 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

相关问题