Наименьшее количество кода, возможное для этого запроса MySQL?
У меня есть запрос MySQL, который:
- получает данные из трех таблиц, связанных уникальными идентификаторами.
- подсчитывает количество игр, сыгранных в каждой категории, от каждого пользователя
- и подсчитывает количество игр, в которые играл каждый пользователь, попадающих в категорию "fps".
Мне кажется, что этот код может быть намного меньше. Как бы я мог сделать этот запрос меньше. http://sqlfiddle.com/#!2 / 6d211/1
Любая помощь ценится, даже если вы просто дайте мне ссылки, чтобы проверить.
2 ответа:
Как правило, неплохо иметь логику соединения как часть предложения
[Inner|Left] Join
, а не как часть предложенияWhere
. В случае упрощения запроса это очищает предложение Where, чтобы обработчик запросов не применял условия фильтра слишком рано, что ограничивает то, что вы хотите сделать в более сложных частях запроса (и влияет на общую производительность запроса).Путем рефакторинга условий соединения мы можем уменьшить запрос до его основного соединения через три таблицы, а затем добавить соединение к специализированному подзапросу, где происходит агрегация. В результате получается только один вложенный запрос, который объединяет наименьшее количество необходимых таблиц.
Вот что я придумал:
SELECT u.user_id ,pg.game_id ,u.user ,g.game ,g.game_cat ,ga.cat_count ,ga.fps_count FROM users u inner join played_games pg on u.user_id = pg.user_id inner join games g on pg.game_id = g.id inner join ( select ipg.user_id ,ig.game_cat ,count(ig.game) cat_count ,sum(case when ig.game_cat = 'fps' then 1 else 0 end) fps_count from played_games ipg inner join games ig on ipg.game_id = ig.id group by ipg.user_id ,ig.game_cat ) ga on g.game_cat = ga.game_cat and pg.user_id = ga.user_id order by ga.fps_count desc ,u.user ,ga.cat_count desc;
Одно из отличий исходного запроса (кроме небольшого переименования) состоит в том, что поле fps_count имеет значение 0 вместо NULL для игроков, которые не играли ни в одну игру FPS. Надеюсь, что это не так критично, а скорее помогает добавить смысл в запрос.
Наконец, я не уверен в контексте того, как это будет использоваться. На мой взгляд, это, вероятно, попытка сделать слишком много как в перечислении каждой игры, в которую играет каждый пользователь (одна цель), так и в обобщении категорий игр, в которые играет каждый пользователь (отдельная цель). Это означает, что сводные данные повторяются несколько раз, например, для пользователей, играющих в несколько игр определенной категории, которые могут быть не идеальными. Моя рекомендация состояла бы в том, чтобы отделить их на два отдельных запроса, хотя я не знаю, удовлетворит ли это ваши конкретные потребности.Надеюсь, это поможет.
Я думал, предоставить ли решение d_mcg или это. Я решил пойти на это. Мне было интересно, какой из них будет быстрее. Это то, что вы можете попробовать и рассказать нам :)
select u.user_id, pg.game_id, u.user, g.game, g.game_cat, (select count(*) from played_games pg2 join games g2 on pg2.game_id = g2.id where pg2.user_id = pg.user_id and g2.game_cat = g.game_cat) cat_count, (select count(*) from played_games pg3 join games g3 on pg3.game_id = g3.id where pg3.user_id = pg.user_id and g3.game_cat = g.game_cat and g.game_cat = 'fps') order_count from users u left join played_games pg on u.user_id = pg.user_id join games g on pg.game_id = g.id order by order_count desc, u.user, cat_count desc