MySQL объясняет: что вызывает "использование временного; использование filesort"
я планирую создать представление с помощью этого SQL SELECT, но объяснение для него показывает, что он использует временный и использует filesort. Я не могу понять, какие индексы мне нужны, чтобы решить эту проблему. В основном, мне интересно, почему он использует filesort intead использования индекса для сортировки.
вот мои таблицы:
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 ответов
в первом запросе вы соединяете таблицу подписей с предложениями пользователей, получаете много строк, а затем группируете результаты, используя некоторые столбцы из предложений пользователей. Но нет индекса для присоединенной таблицы, чтобы помочь с группировкой, как это должно быть определено в ранее присоединенной таблице. Вместо этого вы должны попытаться создать производную таблицу из пользовательских предложений, которые уже сгруппированы 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, потому что только один signature_id будет соответствовать вашему md5 в любом случае. Оптимизатор теперь должен использовать индекс md5 для where и char_index для группировки.
возможно, это поможет, если вы создадите индекс на learning_signatures, который содержит signature_md5 и signature_id (и в этом порядке)
`KEY `md5_id` (`signature_md5`,`signature_id`)?
Я не эксперт MySQL, но я обнаружил, что созданные ключи, которые инкапсулируют предложение where и предложение join, обычно помогают избавиться от временного и filesort
использовать индексы. Найдите поля, где они вам нужны, используя EXPLAIN
по вашим запросам.
если у вас есть в основном только для записи БД (несколько чтений), вы можете воздержаться от использования индексов, поскольку они могут негативно повлиять на производительность записи.