MySQL Объясните: что вызывает 'Использование временного;Использование filesort ' - PullRequest
14 голосов
/ 02 мая 2011

Я планирую создать представление, используя этот SQL SELECT, но объяснение для него показывает, что он использует временный и использует файловую сортировку.Я не могу понять, какие индексы мне нужны, чтобы решить эту проблему.В основном мне интересно, почему он использует файловую сортировку вместо использования индекса для сортировки.

Вот мои таблицы:

CREATE TABLE `learning_signatures` (
  `signature_id` int(11) NOT NULL AUTO_INCREMENT,
  `signature_file` varchar(100) NOT NULL,
  `signature_md5` varchar(32) NOT NULL,
  `image_file` varchar(100) NOT NULL,
  PRIMARY KEY (`signature_id`),
  UNIQUE KEY `unique_signature_md5` (`signature_md5`)
) ENGINE=InnoDB AUTO_INCREMENT=640 DEFAULT CHARSET=latin1

CREATE TABLE `learning_user_suggestions` (
  `user_suggestion_id` int(11) NOT NULL AUTO_INCREMENT,
  `signature_id` int(11) NOT NULL,
  `ch` char(1) NOT NULL,
  `time_suggested` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `user_id` int(11) NOT NULL,
  PRIMARY KEY (`user_suggestion_id`),
  KEY `char_index` (`ch`),
  KEY `ls_sig_id_indx` (`signature_id`),
  KEY `user_id_indx` (`user_id`),
  KEY `sig_char_indx` (`signature_id`,`ch`)
) ENGINE=InnoDB AUTO_INCREMENT=1173 DEFAULT CHARSET=latin1

А вот проблемный оператор SQL, который я планируюиспользуя на мой взгляд:

select ls.signature_id, ls.signature_file, ls.signature_md5, ls.image_file, sug.ch , count(sug.ch) AS suggestion_count
from (`learning_signatures` `ls` left join `learning_user_suggestions` `sug` on(ls.signature_id = sug.signature_id))
group by ls.signature_id, sug.ch;

Вывод из объяснения:

id  select_type table   type    possible_keys                   key             key_len ref                 rows    Extra
1   SIMPLE      ls      ALL     NULL                            NULL            NULL    NULL                514     "Using temporary; Using filesort"
1   SIMPLE      sug     ref     ls_sig_id_indx,sig_char_indx    ls_sig_id_indx  4       wwf.ls.signature_id 1

Другой пример, на этот раз с использованием предложения where:

explain select ls.signature_id, ls.signature_file, ls.signature_md5, ls.image_file, sug.ch , count(sug.ch) AS suggestion_count
from (`learning_signatures` `ls` left join `learning_user_suggestions` `sug` on(ls.signature_id = sug.signature_id))
WHERE signature_md5 = '75f8a5b1176ecc2487b90bacad9bc4c'
group by ls.signature_id, sug.ch;

Объяснение вывода:

id  select_type table   type    possible_keys                key                    key_len ref     rows    Extra
1   SIMPLE      ls      const   unique_signature_md5         unique_signature_md5   34      const   1       "Using temporary; Using filesort"
1   SIMPLE      sug     ref     ls_sig_id_indx,sig_char_indx ls_sig_id_indx         4       const   1   

Ответы [ 3 ]

18 голосов
/ 02 мая 2011

В первом запросе вы присоединяетесь к своей таблице подписей с предложениями пользователей, получаете много строк, а затем группируете результаты, используя несколько столбцов из предложений пользователей. Но для объединенной таблицы не существует индекса, который бы помог в группировке, поскольку его необходимо было бы определить для ранее объединенной таблицы. Вместо этого вам следует попытаться создать производную таблицу из предложений пользователей, которые уже объединены в ch и signature_id, а затем присоединиться к ней:

SELECT ls.signature_id, ls.signature_file, ls.signature_md5, ls.image_file, 
       sug.ch, sug.suggestion_count
FROM learning_signatures ls
LEFT JOIN 
  (SELECT s.signature_id, s.ch, count(s.ch) as suggestion_count
    FROM learning_user_suggestions s 
    GROUP BY s.signature_id, s.ch ) as sug
ON ls.signature_id = sug.signature_id

Оптимизатор должен теперь иметь возможность использовать ваш индекс sig_char_indx для группирования, производная таблица будет не больше вашей таблицы подписей, и вы объедините обе таблицы, используя уникальный столбец. Вам все равно придется выполнить полное сканирование таблицы подписей, но этого нельзя избежать, потому что вы все равно выбираете все.

Что касается второго запроса, если вы хотите ограничить подписи одной подписью, просто добавьте

WHERE ls.signature_md5='75f8a5b1176ecc2487b90bacad9bc4c'

до конца предыдущего запроса и сгруппировать только по s.ch, потому что только один сигнатурный идентификатор все равно будет соответствовать вашему md5. Оптимизатор теперь должен использовать индекс md5 для where и char_index для группировки.

0 голосов
/ 22 июня 2017

Используйте индексы. Найдите поля, в которых они вам нужны, используя EXPLAIN в запросах.

Если, однако, у вас есть БД, предназначенная только для записи (с небольшим чтением), вы можете отказаться от использования индексов, поскольку они могут негативно повлиять на производительность записи.

0 голосов
/ 02 мая 2011

Может быть, это поможет, если вы создадите индекс для learning_signatures, который содержит и signature_md5, и signature_id (и в этом порядке)

`KEY `md5_id` (`signature_md5`,`signature_id`)?

Я не эксперт по MySQL, но обнаружил, что создал ключи, которые инкапсулируюти предложение where, и предложение join обычно помогают избавиться от временного и filesort

...