0

MySQL データベースに関する質問があり、何が最も効率的かについて意見を求めたいと思います。

私の問題は次のとおりです。

ボード ゲーム Web サイトのプレミアム機能を開発しています。プレミアム機能の 1 つは、ユーザーがプレイしたすべてのゲームが「永久に」保存されることです (ユーザーが後で検索できるようにするため)。通常のユーザーの場合、18 か月以上前のゲームは削除されます。

ここで、通常の非プレミアム ユーザーのゲーム (18 か月以上前のもの) を削除し、プレミアム ユーザーのゲームを保持する効果的な方法を見つける必要があります。

単純化すると、2 つのテーブルが得られました (実際には、各ゲームの参加者を格納するテーブルがもう 1 つあります)。

ゲーム、

 id=INT
 play_date=DATETIME
 end_score=INT
 player_id_1=INT
 player_id_2=INT

ユーザー、

 id=INT
 premium=BOOLEAN (true=enabled, false=not enabled)

ユーザー テーブルには 300.000 行以上が含まれていますが、ゲーム テーブルには数百万行が含まれています。毎日約 20.000 ゲームがゲーム テーブルに追加されます。

非プレミアム ユーザーから 18 か月以上前のゲームを削除する最も効率的な方法は何でしょうか。

これまでのところ、毎週月曜日の朝に、すべてのユーザーに対して 18 か月以上前のゲームを削除しました。

ここで、プレミアム値とゲームの日付を考慮する必要があります。

いくつかの解決策 (?):

  • Games テーブルの何百万もの行について話していますが、テーブルを JOIN していますが、これはダメでしょうか?
  • 18 か月より古い各ゲーム エントリを取得し、player_id_1 と player_id_2 から各ユーザー エントリを取得し、これらのいずれかがプレミアムである場合はゲームをそのままにし、18 か月より古い場合は削除します。したがって、1 週間で、これは 20k*7=140k 相当のゲームになる可能性があります。
  • 1時間ごとに行うことを除いて、上記のソリューション。次に、取得して確認する必要があるゲームが約 1000 あります。
  • ?? Games テーブルにある種のヘルパー変数を追加しますか? しかし、ユーザーがプレミアムの使用をやめたらどうなるでしょうか....

どんなヒントでも大歓迎です...

4

4 に答える 4

3

有効期限とその上のインデックスを使用します。

その列でNULLを許可します。

プレミアムユーザーのゲームはNULLになります。

Expire_date <sysdateのゲームを削除すると、インデックスが使用されます。つまり、INDEX RANGE SCANです(注文可能なインデックス上にある必要があります。つまり、ある種のBツリー内部表現です...しかし、私はMySQLのスペシャリストではありません。 )。

編集

または、expire_dateを使用してレジストリPKの別のテーブルを管理します。したがって、プレミアムユーザーレコードがスペースを占有することはありません。次に、pkが入っているxxxから削除を実行します(expiring_tableからpkを選択します)。

しかし、それは以前のソリューションに比べてあまり良い拡張ではありません。

年齢

たぶんあなたは年齢を使うことができます(例えば1年齢= 1ヶ月)。そして、テーブルにフィールド「month_to_live」を設定します。毎月、nullではないすべてのレコードのフィールド+=1を更新します。それは等式フィルターを使用します。しかし、前に言ったように、私は専門家ではないので、それからどれだけの最適化を得ることができるかわかりません)。

私はexpire_dateフィールドを主張する必要があります(そして、レコードを削除するときに余分なオーバーヘッドを発生させることなく、ライブ期間を誰にでも個別に延長する追加の機能があります)。

于 2010-01-22T15:17:16.657 に答える
1

データベースのダンプをダウンロードし、コンピューターでベンチマークを実行します。これにより、さまざまなソリューションのパフォーマンスについてかなり良いアイデアが得られるはずです。

それとは別に、これらのSQLクエリの質問に対する通常の回答です。クエリで「explain」を実行し、正しいインデックスがあることを確認してください。

于 2010-01-22T15:16:48.833 に答える
0

ユーザーがステータスを変更するたびにゲームテーブルを更新するソリューションは不要で遅いため、避ける必要があります。

これが1つです。毎日同じ時間にクエリを実行するとします。

DELETE games FROM games
JOIN users u1 ON (u1.id=games.player1_id AND NOT u1.premium)
JOIN users u2 ON (u1.id=games.player2_id AND NOT u2.premium)
WHERE games.play_date BETWEEN DATE_SUB( now(), INTERVAL 18 MONTH 1 DAY 1 HOUR)
AND DATE_SUB( now(), INTERVAL 18 MONTH )

もちろん、ゲーム ( play_date ) のインデックスが必要です。

ここでの考え方は、日付範囲チェックでは、削除が必要な可能性があり、昨日のクエリでまだ調査されていないゲームのみを調査するというものです。「ローリングウィンドウ」の一種。

それどころか、これは:

WHERE games.play_date < DATE_SUB( now(), INTERVAL 18 MONTH )

テーブル内のすべての既存のゲームを毎回検査し、非常に遅くなります。

于 2011-06-07T08:51:33.050 に答える
0

JOINing はそれほど悪くないはずです。そのクエリを「ライブ」で実行していないと思いますか? 別のオプションは、ゲームを表示するときにクエリを実行することです。ユーザーがプレミアムの場合は制限を行わず、それ以外の場合は範囲​​を制限します。

于 2010-01-22T15:19:04.070 に答える