此MySQL查询可能的代码量最少?

时间:2012-03-24 03:06:14

标签: mysql select count group-by left-join

我有一个MySQL查询:

  • 从唯一ID链接的三个表中获取数据。
  • 计算每个用户在每个类别中玩的游戏数量
  • 并计算每个用户在“fps”类别下玩过的游戏数量

在我看来,这段代码可能要小得多。我该如何缩小这个查询。 http://sqlfiddle.com/#!2/6d211/1

即使您只是给我链接签出,任何帮助都会受到赞赏。

2 个答案:

答案 0 :(得分:1)

通常,最好将连接逻辑作为[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游戏的玩家,fps_count字段的值为0而不是NULL。希望这不是那么重要,而是有助于为查询添加含义。

最后,我不确定如何使用它的背景。在我看来,它可能试图在列出每个用户玩的每个游戏(一个目标)和总结每个用户玩的游戏类别(一个单独的目标)方面做太多。这意味着摘要细节被重复多次,例如,对于玩特定类别的多个游戏的用户而言,这可能并不理想。我的建议是将这些问题分成两个单独的查询,但我不知道这是否符合您的具体需求。

希望这有帮助。

答案 1 :(得分:0)

我在考虑是否提供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