【发布时间】:2010-05-07 13:20:14
【问题描述】:
我需要优化一个查询,以获得永远需要的排名(查询本身有效,但我知道这很糟糕,我刚刚尝试了很多记录,但它给出了超时)。
我将简要解释模型。我有 3 张桌子:player、team 和 player_team。我有球员,他们可以属于一个球队。听起来很明显,球员存储在球员表中,球队存储在球队中。在我的应用程序中,每个玩家都可以随时切换团队,并且必须保留日志。但是,在给定时间,一名球员被认为只属于一支球队。玩家的当前队伍是他最后加入的队伍。
我认为球员和球队的结构并不相关。我每个都有一个 id 列 PK。在 player_team 我有:
id (PK)
player_id (FK -> player.id)
team_id (FK -> team.id)
现在,每个团队都会为每个加入的玩家分配一个分数。所以,现在,我想获得前 N 支球员数量最多的球队的排名。
我的第一个想法是首先从 player_team 获取当前玩家(即每个玩家的最高记录;该记录必须是玩家当前的团队)。我没有找到一种简单的方法(尝试 GROUP BY player_team.player_id HAVING player_team.id = MAX(player_team.id),但这并没有成功。
我尝试了一些无效的查询,但设法让这个工作正常。
SELECT
COUNT(*) AS total,
pt.team_id,
p.facebook_uid AS owner_uid,
t.color
FROM
player_team pt
JOIN player p ON (p.id = pt.player_id)
JOIN team t ON (t.id = pt.team_id)
WHERE
pt.id IN (
SELECT max(J.id)
FROM player_team J
GROUP BY J.player_id
)
GROUP BY
pt.team_id
ORDER BY
total DESC
LIMIT 50
正如我所说,它可以工作,但看起来很糟糕,性能更差,所以我确信一定有更好的方法。任何人有任何优化这个的想法?
顺便说一句,我正在使用 mysql。
提前致谢
添加解释。 (抱歉,不知道如何正确格式化)
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t ALL PRIMARY NULL NULL NULL 5000 Using temporary; Using filesort
1 PRIMARY pt ref FKplayer_pt77082,FKplayer_pt265938,new_index FKplayer_pt77082 4 t.id 30 Using where
1 PRIMARY p eq_ref PRIMARY PRIMARY 4 pt.player_id 1
2 DEPENDENT SUBQUERY J index NULL new_index 8 NULL 150000 Using index
【问题讨论】:
-
您是否要永久离开 player_team 中曾经发生过的所有球员球队组合?您是否没有以任何方式对此进行标记(历史关系为 0,当前关系为 1 的列会很好)?
-
是的,我要离开组合,因为我必须保留日志。我想过拥有一个当前的标志,如果没有更好的选择,我可能会这样做。但我想也许有更好的方法。 (我是 sql 菜鸟!)不过,谢谢你的建议。
-
您是否使用了生成此表的 Web 框架? (顾名思义,我认为 Rails 使用相同的方案)如果是这样,您可以更改您的 Rails 模型,使其具有用于此连接的所谓直通模型并附加数据,例如成员资格是否为最新。如果没有这个,我看不出你如何跟踪没有更换球队但不是某人球队当前成员的球员。 (诚然,我可能不了解您的 facebook 应用程序的域)
-
@marr75。不,我只是习惯了这种命名惯例,因为我已经习惯了,但这是普通的 PHP + mysql。
-
酷,有道理。您还可以为连接表上的连接列添加唯一约束。或者查询中某处的不同子句,你可能读得很重,所以约束会更好。
标签: mysql optimization subquery ranking