2016-03-10 3 views
1

mysql-5.6.24-win32.1432006610MySQL: почему все еще используется «fileort» при использовании индексов?

У меня есть две таблицы для сообщений пользователей.

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 не в ИНЕКЕ

Ниже запрос получает все сообщения, в том числе тела сообщения данного идентификатора пользователя:

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 | 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 в ИНЕКЕ

Этот запрос такой же, как показано выше, за исключением ИНЕКЕ:

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 | 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, а другой нет.


Update

Пытались использовать 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 

идентификатор является последним, потому что это ссылка на ваш вторичный индекс для первичного ключа.

В первом сценарии вы фильтруете по uid, а затем сортируете по id. Проблема в том, что MySQL не может предположить, что идентификатор заказан должным образом, поскольку индекс фактически упорядочивается filterId перед фильтром по id.

например:

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

Поэтому этот показатель не может быть использован для сортировки, так как сортировка индекса, отличается от порядка по п.

Теперь, мой вопрос: почему вы пытаетесь избежать файлового управления? Если вы не сталкиваетесь с проблемами производительности, использование filesort отлично. Несмотря на имя, сортировка выполняется в памяти, если не указано иное (с использованием временного).

+0

Спасибо, ты хороший! – Zach

+0

Я попробовал 'ORDER BY TMessage.folderId, TMessage.id DESC' в первом запросе,' Использование filesort' все еще существует. Как вы сказали, это приемлемо в большинстве случаев, но я все еще удивляюсь, почему в этом случае. – Zach

+0

@ Zach ой, я удалю этот бит из моего ответа, тогда – ESG