0

重複の可能性:
Mysql ランク関数

私はランクのウェブサイトを作っており、各ユーザーはレベルに基づいて独自のランクを持っています. 1 位が最高ランクで、ユーザー数が 350,000 であるため、最低ランクは 350,000 位になります。

ユーザーが他のユーザーと同じランクを持つことはできません。現在、新しいユーザーが追加されると、そのレベルが計算されます。計算後、スクリプトは各ユーザーを 1 人ずつ調べて新しいランクを計算することにより、ランクを「再構築」します。

クエリの説明は次のとおりです。

  • 「Id」は、データベース内のメンバーの ID です。
  • 「RankNum」はレベルです。名前を変更する必要があります。
  • 「ランク」は、1 位から 350000 位までの固有のランクです。

これが私の現在のスクリプトです:

function RebuildRanks() {
    $qD = mysql_query("SELECT `Id`,`RankNum` FROM `Members` ORDER BY `Rank` DESC, `Id` ASC");
    $rowsD = mysql_num_rows($qD);

    $curRank = 0;

    for($x = 1; $x <= $rowsD; $x++) {
        $rowD = mysql_fetch_array($qD);

        $curRank++;
        if($rowD['RankNum'] != $curRank) {
            if($curRank != 0) {
                mysql_query("UPDATE `Members` SET `RankNum`='$curRank' WHERE `Id`='".$rowD['Id']."'");
            }
        }
    }

    return true;
}

ユーザー数が 350,000 の場合、これは非常に遅くなる傾向があります。基本的に、データベースではランク("ORDER BY `Rank` DESC") がレベルであるため、クエリはそれらを並べ替えます。残念ながら、残りのプロセスは遅いです。

この方法で 350,000 人のユーザーすべてを処理するには、約 97 秒かかります。これをより効率的かつ迅速に実行するための解決策はありますか?

4

3 に答える 3

2

新しいユーザーの NewNum を計算し、この後のすべての数値を増やします

 UPDATE Members SET Rank = Rank+1  WHERE Rank > NewNum

編集RankNum を Rank に変更しました。編集後に質問を確認しました

于 2012-10-20T21:32:40.660 に答える
1

RebuildRanks() 関数は、ユーザーベースが拡大するにつれて、引き続きパフォーマンスのボトルネックになります。新しいユーザーが参加するたびに再ランキングを回避するシステムを考案することをお勧めします。役立つ可能性のあるソリューションの例を次に示します。

ユーザーをスコア別にソートしたハッシュである新しいテーブル (ScoreMap) を追加します (あいまいさをなくすために、「ランク」の代わりにこの用語を使用します)。

CREATE TABLE ScoreMap (
  Score BIGINT NOT NULL, 
  Id BIGINT NOT NULL, 
  UNIQUE INDEX (Score), 
  UNIQUE INDEX (Id)
);

新しいユーザーが参加すると、スコアを計算し、この新しいテーブルに挿入します。Score に競合がある場合は、それを解決できます (2 人のユーザーが同じ RankNum を持つことができない場合は、Score に対して何らかのタイブレーク機能が必要です。必要に応じてこのテーブル内でユーザーを移動します)。

次に、ScoreMap テーブルにクエリを実行します。

SELECT COUNT(*) FROM ScoreMap WHERE Score >= [the score you just calculated]

それがあなたの新しいユーザーのランク番号です。新しいユーザーよりもスコアが悪い人は全員、ランクが 1 上がります。このランクは、ログインしたり、キャッシュを前に置いたりするたびに、すぐに、定期的に更新できます。

PS: ランク スコアリング関数を 0 から非常に大きな数 (1 兆など) の間の BIGINT になるように正規化します。これにより、新しいテーブルに挿入する際の衝突を回避できます。基本的にスコアをハッシュ関数として使用しているため、この範囲で均等な分布を求めたいと考えています。

于 2012-10-20T21:58:44.480 に答える
0

それを行う1つの方法は、確かに次のようにクエリステートメントを使用することです(テストされていません):

UPDATE `Members`
SET `RankNum` = (@newRank := @newRank + 1)
ORDER BY `Rank` DESC, `Id` ASC, @newRank := 0

注文の更新と処理を同時に行います。

于 2012-10-20T22:22:46.857 に答える