MySQL:为什么还要使用filesort'什么时候使用索引?

时间:2016-03-10 13:17:53

标签: mysql filesort

的MySQL-5.6.24-win32.1432006610

我有两张桌子供用户使用'消息。

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       TMessage.uid=@uid
                #AND TMessage.folderId=@folderId
ORDER BY    TMessage.id DESC
;

EXPLAIN结果是:

mysql> EXPLAIN
-> SELECT *
->  FROM            TMessage
->  INNER JOIN      TMessageBody
->  ON              TMessage.msgBodyId=TMessageBody.id
->  WHERE           TMessage.uid=@uid
->                      #AND TMessage.folderId=@folderId
->  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.当folderId位于WHERE子句中时,.FileSort消失

除WHERE子句外,查询与上面的查询相同:

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

EXPLAIN
SELECT *
FROM        TMessage
INNER JOIN  TMessageBody 
ON          TMessage.msgBodyId=TMessageBody.id
WHERE       TMessage.uid=@uid
              AND TMessage.folderId=@folderId
ORDER BY    TMessage.id DESC
;

EXPLAIN结果是:

mysql> EXPLAIN
-> SELECT *
->  FROM            TMessage
->  INNER JOIN      TMessageBody
->  ON              TMessage.msgBodyId=TMessageBody.id
->  WHERE           TMessage.uid=@uid
->                            AND TMessage.folderId=@folderId
->  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       TMessage.uid=@uid
->                   #AND TMessage.folderId=@folderId
->  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)

1 个答案:

答案 0 :(得分:3)

将索引视为连接值。

在这种情况下,您的索引是

uid | folderId | id

id是最后一个,因为它是您的主键的辅助索引中的引用。

在第一个场景中,您按uid过滤,然后按ID排序。问题是MySQL不能假设id是有序的,因为索引实际上是由filterId排序的,然后才被id过滤。

例如:

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

因此,该索引不能用于排序,因为索引的排序与order by子句不同。

现在,我的问题是:你为什么要避免使用filesort?除非遇到性能问题,否则使用filesort是完全正常的。尽管名称如此,但排序是在内存中完成的,除非另有说明(使用临时)。