创建具有唯一用户的toplist

时间:2011-01-18 13:09:29

标签: sql mysql

我有一个包含字段id, user_id, condition1, condition2, condition3, score的表格。每个用户可以在表中有多行。我现在要做的是创建几个顶级列表。例如,它可能是condition1 = foo的顶级列表,我只想计算每个用户一次,但我希望每个用户都有完整的最佳行。

所以SELECT user_id, MAX(score) AS s FROM table WHERE condition1 = foo ORDER BY s DESC LIMIT 50不起作用。

我想要这么多不同的名单,所以创建第二个表,我存储用户最好的结果不是一个真正的选择。因为每个用户可能会有超过100个不同的最佳结果。

重要的两件事是快速获得前50名。但是还要确定特定用户所处的位置(通过检查有多少独特用户得分高于特定用户,这非常容易)。

更新:我测试了Thomas和Quassnoi的想法,Thomas的想法用了11秒,Quassnoi用了4.5秒。

然后我想出了另一种方法:

SELECT (  
    SELECT id  
    FROM table AS ti
    WHERE ti.user_id = t.user_id
        AND condition1 = foo
    ORDER BY score DESC
    LIMIT 1
)
FROM table as t
WHERE condition1 = foo
GROUP BY user_id
ORDER BY MAX(score) DESC
LIMIT 50

然后我再做一个查询,其中挑选出所有行WHERE id IN(all ids returned from the first query),这种方式需要0.4秒。

这是一个很好的方法吗?或者我只是在我的testdata中幸运?

3 个答案:

答案 0 :(得分:0)

未经测试,但我认为您缺少GROUP BY子句:

SELECT user_id, MAX(score) AS s FROM table WHERE condition1 = foo GROUP BY user_id ORDER BY s DESC LIMIT 50

答案 1 :(得分:0)

SELECT  *
FROM    mytable m
WHERE   m.id = 
        (
        SELECT  id
        FROM    mytable mi
        WHERE   mi.user_id = m.user_id
                AND mi.condition1 = 'foo'
        ORDER BY
                score DESC, id DESC
        LIMIT 1
        )
ORDER BY
        score DESC
LIMIT 50

SELECT  m.*
FROM    users u
JOIN    mytable m
ON      mi.id = 
        (
        SELECT  id
        FROM    mytable mi
        WHERE   mi.user_id = u.id
        ORDER BY
                score DESC, id DESC
        LIMIT 1
        )
ORDER BY
        score DESC
LIMIT 50

哪一个更快取决于分数的分布,但第一个分数通常更快,除非你真的很少有很多分数的用户真正经常联系。

为了使其快速起作用,您应该使用复合索引:

mytable (score, id)

加上每个过滤组合的索引,如下所示:

mytable (user_id, score, id) -- for no filtering
mytable (user_id, condition1, score, id) -- for filtering on condition1

答案 2 :(得分:0)

Select T.Id, T.user_id, T.condition1, T.condition2, T.condition3, T.score
From Table As T
Where Exists    (
                Select 1
                From Table As T2
                Where T2.user_id = T.user_id
                    And T2.condition1 = 'foo'
                Having Max(T2.score) = T.score
                )
Limit 50