0

アプリケーションにリーダー ボードを実装しています。数回ごとに更新したいと考えています。そのために、リーダー ボードの 2 つのテーブルを作成しました。それぞれが次のようになります。

user_id, score, rank

これは私の更新クエリです:

select score from leaderboard order by score for update;
select(@rankCounter := 0);
update leaderboard set rank = (select(@rankCounter := @rankCounter + 1)) order by score desc;

アクティブなテーブルをクエリに使用していますが、数回ごとにアクティブなテーブルを切り替えます。

現在、4M raw を更新するのに (私のマシンでは) 約 3 分かかります。必要な CPU の量を減らしたいのですが、更新に時間がかかることは気にしません。

どうやってやるの?

4

1 に答える 1

0

... ON leaderboard (score)並べ替え操作を避けるために、 index を追加することをお勧めします。また、不要な SELECT を UPDATE ステートメントから削除することをお勧めします (ただし、それがパフォーマンスに影響するかどうかはわかりませんが、そのコンテキストでは SELECT キーワードは必要ありません。

ソート操作は確かにいくらかの CPU を使用します。UPDATE ステートメント内の SELECT がオプティマイザーによって無視されるのか、それとも計画がそこにある (不要な?) SELECT と何らかの形で異なるのかは、私には明らかではありません。(そのコンテキストに SELECT キーワードを含める目的は何ですか?)

また、リーダーボード テーブルのすべての行でロックを取得するために、すべての行からスコア値を返す必要はありません。その SELECT ステートメントの ORDER BY も CPU サイクルを消費している可能性があります (score先行列としてのインデックスがない場合)。4M 行の結果セットの不要な準備も CPU サイクルを消費しています。

UPDATE ステートメント自体が必要なロックを取得するときに、SELECT ... FOR UPDATE を使用して、テーブル内のすべての行のロックを取得する必要がある理由は明らかではありません。(SELECT ... FOR UPDATE ステートメントは、BEGIN TRANSACTION のコンテキストでのみ、または自動コミットが無効になっている場合にのみロックを取得します。(ここでleaderboardは、それが InnoDB テーブルであると想定しています。)


MySQL は、並べ替え操作を回避するためにインデックスを利用できる場合があります。

CREATE INDEX leaderboard_IX1 ON leaderboard (score) ;

そして、これはランク列を更新するのに十分なはずです:

SET @rankCounter := 0;
UPDATE leaderboard
  SET rank = @rankCounter := @rankCounter + 1
ORDER BY score DESC ;
于 2013-01-16T17:01:39.517 に答える