Доброго времени суток. Помогите решить задачу с MySQL (знаком довольно плохо):
Есть 5 таблиц:
games (id, name, info) platforms (id, name, info) categories (im, name, info) games_platforms_assign (game_id, platform_id) games_categories_assign (game_id, category_id)
Соответственно, таблица games имеет связи многие-ко-многим с таблицами platforms и categories. Необходимо выбирать все games, относящиеся к заданным platforms.name и categories.name. Делаю так:
SELECT games.* FROM games JOIN games_platforms_assign On games.id = games_platforms_assign.game_id JOIN platforms ON platforms.name = 'pc' AND games_platforms_assign.platform_id = platforms.id JOIN games_categories_assign ON games.id = games_categories_assign.game_id JOIN categories ON categories.name = 'action' AND games_categories_assign.category_id = categories.id;
Результат выборки соответствует ожиданиям, но скорость выполнения ужасно медленна. Пробовал с помощью вложенных SELECTов - получалось в разы медленнее.
Как переделать запрос для существенного ускорения выполнения? Или, в крайнем случае, как лучше переделать структуру базы данных под подобные запросы?
Я бы перенёс изменяемые условия в WHERE. Это(в некоторых сценариях) позволит переиспользовать результат prepare.
Использование псевдонимов таблиц
SELECT g.id, g.name, g.info
FROM games g
JOIN games_platforms_assign gp On g.id = gp.game_id
JOIN platforms p ON gp.platform_id = p.id
JOIN games_categories_assign gc ON g.id = gc.game_id
JOIN categories c ON gc.category_id = c.id
WHERE p.name = ? AND c.name = ?
Абсолютно необходимо создать индексы(а лучше foreign keys) на поля-связки (game_id, platform_id, category_id) и индексы на поля поиска(name).
После этого можно смотреть EXPLAIN, чтобы убедиться в том какие индексы используются, при необходимости можно добавить композитных индексов.
SELECT g.id g.name g.info
FROM games g
LTFT JOIN games_platforms_assign gpa ON (gpa.game_id = g.id)
LEFT JOIN games_categories_assign gca ON (gca.game_id = g.id)
LEFT JOIN platforms p ON (p.id = gpa.game_id)
LEFT JOIN categories c ON (c.id = gca.game_id)
WHERE p.name = .... AND c.name = ....
Сборка персонального компьютера от Artline: умный выбор для современных пользователей