2011-12-30 7 views
3

スコアに基づいてユーザーのランクを格納しようとしています。それはすべて1つのテーブルであり、ネクタイがある場合はランクをスキップします。たとえば:シンプルな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; 

しかし、このその関係で、ネクタイをサポートしていないか、ネクタイをスキップしています。

私はできるだけ少ないクエリで、またジョインはしないで(時間がかかるように)、この再ランキングを実現したいと思います。

私は2つの列追加することによって、望ましい結果を得ることができた - 次のコードで - 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

私はあなたがこのデザインの選択には正当な理由があると確信していますが、私はあなたがデータベースからすべてのランクを離れるべきだと思います。 1人のユーザーのスコアの変更ごとにテーブル全体を更新すると、ほぼすべてのサイズテーブルで深刻なパフォーマンスの問題が発生する可能性があります。私はその選択を再考することをお勧めします。私はスコアでテーブルを単純にソートし、アプリケーションコードにランクを割り当てるというアドバイスをします。

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」)。私は、私は必要な値を更新し、取得するために

:しかし、それは私がランクを計算し、以下の方法を配置

+0

+1、それは私がしているものです。絶対に必要な場合を除き、計算カラムを格納するのは正しいとは思われません。書き込みのためにロックが必要ないので、列の計算のパフォーマンスはおそらく格納よりも優れています。 –

-1

(クエリに対応するLIMITを置くものとする)「ランク上位Nを選択する」ために、まだ良いことです最初に追加し、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; 
関連する問題