Как улучшить скорость выборки из SQL?
Я не эксперт в индексах MySQL, но я видел много учебников, все равно моя страница загружается за 7 секунд, используя PHP.
У меня есть около 50k строк и 30 столбцов в таблицах MySQL.
Как я могу улучшить скорость извлечения данных MySQL? Что-нибудь, что я могу улучшить в этом ниже запросе?
SELECT tmdb_movies.movie_title,tmdb_movies.budget,tmdb_movies.original_language,tmdb_movies.original_title
,translations.translations_english_name
,videos.videos_name,videos.videos_key
FROM tmdb_movies
LEFT JOIN
(
SELECT
translations_tmdb_id
,GROUP_CONCAT(DISTINCT translations.translations_english_name SEPARATOR ', ') AS translations_english_name
FROM translations
GROUP BY translations_tmdb_id
) translations ON translations.translations_tmdb_id = tmdb_movies.tmdb_id
LEFT JOIN
(
SELECT
videos_tmdb_id
,GROUP_CONCAT(DISTINCT videos.videos_name) as videos_name
,GROUP_CONCAT(DISTINCT videos.videos_key) as videos_key
FROM videos
GROUP BY videos_tmdb_id
) videos ON videos.videos_tmdb_id = tmdb_movies.tmdb_id
Where tmdb_movies.tmdb_id= '$tmdb_id'
Здесь я использую tmdb_id
для соединения всех таблиц. tmdb_id
,translations_tmdb_id
и videos_tmdb_id
индексируются в MySQL.
Вот пример моей структуры таблицы MySQL:
tmdb_movies
таблица:
tmdb_id movie_title
1 Logan
2 Iron Man
3 Superman
translations
таблица
translations_tmdb_id translations_english_name
1 English
1 Hindi
1 French
2 English
2 Spanish
2 Hindi
videos
таблица
videos_tmdb_id videos_name
1 Official Trailer
1 Trailer 2
2 Trailer 1
2 Trailer 2 HD
3 Superman Trailer 1
3 Superman Trailer 2
2 ответа:
- Почему
GROUP_CONCAT(DISTINCT ...)
? Здесь нет дубликатов.- вы выбираете данные только для одного фильма. Но ваши производные таблицы считывают и агрегируют все фильмы. Большой оптимизатор будет просматривать это и только агрегировать записи для этого одного фильма. Если бы это был Оракул, я бы ожидал именно этого. Но с MySQL? Я бы на это не рассчитывал. Поэтому добавьте предложение where к вашим подзапросам.
- Вы не должны выбирать имена и ключи видео без предложения order by. Закажите их так, чтобы у обоих был один и тот же порядок, то есть первое имя соответствует первому ключу и т. д.
Вот ваш запрос переписан заново:
SELECT m.movie_title, m.budget, m.original_language, m.original_title, t.translations_english_names, v.videos_names, v.videos_keys FROM tmdb_movies m CROSS JOIN ( SELECT GROUP_CONCAT(translations_english_name SEPARATOR ', ') AS translations_english_names FROM translations WHERE translations_tmdb_id = @tmdb_id ) t CROSS JOIN ( SELECT GROUP_CONCAT(videos_name ORDER BY videos_name) as videos_names, GROUP_CONCAT(videos_key ORDER BY videos_name) as videos_keys FROM videos WHERE videos_tmdb_id = @tmdb_id ) v WHERE m.tmdb_id = @tmdb_id;
И вот какие индексы вы должны использовать:
create index idxm on tmdb_movies(tmdb_id); -- if tmdb_id is PK, you have this already create index idxt on translations(translations_tmdb_id, translations_english_name); create index idxv on videos(videos_tmdb_id, videos_name, videos_key);
Ваш основной оператор
SELECT
, вероятно, в порядке; вы фильтруете по первичному ключу autoincrementing.Это два подзапроса, в которых могут быть заложены возможности для повышения производительности.
Первый:
SELECT translations_tmdb_id, GROUP_CONCAT( DISTINCT translations.translations_english_name SEPARATOR ', ') AS translations_english_name FROM translations GROUP BY translations_tmdb_id
Составной индекс (иногда называемый составным индексом или многоколоночным индексом) on
translations_tmdb_id, translations_english_name
может очень сильно помочь этому подзапросу. Почему? Он может помочь как сGROUP BY
, так и сDISTINCT
частями запроса.Второй один:
SELECT videos_tmdb_id ,GROUP_CONCAT(DISTINCT videos.videos_name) as videos_name ,GROUP_CONCAT(DISTINCT videos.videos_key) as videos_key FROM videos GROUP BY videos_tmdb_id
Применяется тот же принцип, но два различных предложения
DISTINCT
немного замедлят процесс. Попробуйте использовать составной индекс наvideos_tmdb_id, videos_name, videos_key
. Это должно помочь.