2011-12-30 66 views
3

我試圖存儲用戶的排名基於分數,所有它一張桌子,並跳過隊伍,當有領帶。例如:簡單的MySQL更新排名與關係

ID Score Rank 
2 23 1 
4 17 2 
1 17 2 
5 10 4 
3 2  5 

用戶每次的分數被更新,整個表中的排名也必須更新,所以得分更新後,下面的查詢運行:

SET @rank=0; 
UPDATE users SET rank= @rank:= (@rank+1) ORDER BY score DESC; 

但這不支持關係,或者在關係之後跳過排名數字。

我想在儘可能少的查詢中實現這種重新排名並且沒有聯接(因爲它們看起來相當耗時)。

我能夠通過增加兩列,以獲得期望的結果 - last_score和tie_build_up - 用下面的代碼:

SET @rank=0, @last_score = null, @tie_build_up = 0; 
UPDATE users SET 
    rank= @rank:= if(@last_score = score, @rank, @[email protected]_build_up+1), 
    tie_build_up= @tie_build_up:= if(@last_score = score, @tie_build_up+1, 0), 
    last_score= @last_score:= score, ORDER BY score DESC; 

我不希望這些額外的列,但我不能讓單查詢工作沒有他們。

任何想法?

謝謝。

回答

0

我相信你對這個設計選擇有很好的理由,但我認爲你應該把數據庫的排名放在一起。更新整個表對於一個用戶的分數的每一個變化,幾乎可以在任何大小的表中引起非常嚴重的性能問題。我建議你重新考慮這個選擇。我會建議簡單地按表格對錶格進行排序,並在應用程序代碼中分配排名。

3

下面是一個備用解決方案:根本不存儲行列! :-)

您可以即時計算它們。

例子:

SELECT id, (@next_rank := IF(@score <> score, 1, 0)) nr, 
      (@score := score) score, (@r := IF(@next_rank = 1, @r + 1, @r)) rank 
FROM rank, (SELECT @r := 0) dummy1 
ORDER BY score DESC; 

結果:

+------+----+-------+------+ 
    | id | nr | score | rank | 
    +------+----+-------+------+ 
    | 2 | 1 | 23 | 1 | 
    | 4 | 1 | 17 | 2 | 
    | 1 | 0 | 17 | 2 | 
    | 5 | 1 | 10 | 3 | 
    | 3 | 1 |  2 | 4 | 
    +------+----+-------+------+ 

nr這裏是aт若干輔助列表示是否要指派下一個行還是不行。

例如,您可以將此查詢包裝在另一個select中並執行分頁。

SELECT id, score, rank 
FROM (SELECT id, (@next_rank := IF(@score <> score, 1, 0)) nr, 
      (@score := score) score, (@r := IF(@next_rank = 1, @r + 1, @r)) rank 
     FROM rank, (SELECT @r := 0) dummy1 
     ORDER BY score DESC) t 
     WHERE rank > 1 and rank < 3; 

結果:

+------+-------+------+ 
    | id | score | rank | 
    +------+-------+------+ 
    | 4 | 17 | 2 | 
    | 1 | 17 | 2 | 
    +------+-------+------+ 

注意:因爲現在rank是一個計算列,你不能索引,並有效頁面遠到的數據集(即「選擇從隊伍中記錄3000至3010「)。但它是還是不錯的「選擇前N個排名」(前提是你把查詢相應LIMIT

+0

+1,這是我會做的。除非絕對必要,否則存儲計算列似乎不正確。計算列的性能可能比存儲更好,因爲寫入不需要鎖定。 – 2011-12-31 04:25:32

-1

我計算的等級和地位的方式如下:

更新得到我所需要的價值觀,我首先添加它們,再添加1並減去原始值。這樣我就不需要桌子內的任何幫助欄;

SET @rank=0; 
SET @position=0; 
SET @last_points=null; 

UPDATE tip_invitation 
set 
    rank = @rank:=if(@last_points = points, @rank, @rank + 1), 
    position = ((@last_points := points)-points) + (@position := @position+1) 
where 
    tippgemeinschaft_id = 1 ORDER BY points DESC;