私たちのオンラインコンテストシステムには、standings
整数列の頻繁に変更されるテーブルがあります(user_id, score)
。どちらも一意の制約でインデックスが付けられます。2種類のクエリが必要です。
- テーブル
score
にない場合は、スコアが挿入された場合にスコアが占める1ベースの位置を返します。 - 表にa
user_id
を指定して、対応するスコアの位置を返します。
どちらの場合も、位置はスコアの昇順を基準にしています。現在テーブルにあるすべてのスコアよりも小さい新しいスコアの位置は1になります。
ここが難しい部分です。おそらく、テーブルスキャンを行う余裕はありません。テーブルには最大1,000万のレコードが含まれる可能性があり、1秒あたり少なくとも40のクエリを処理する必要があります。
PostgreSQLでこれを行う方法は?
Berkeley DBには、論理レコード番号が有効なBツリーを使用する非SQLソリューションがあります。簡単に十分なパフォーマンスが得られます。しかし、PostgreSQLクエリを使用して再実装することでBDBを取り除きたいと思います。私は明白なことを試みました
select 1+count(*) from standings where score < ? limit 1;
これにより、テーブルスキャンが発生します。
BDBの論理レコード番号機能では、編集ごとにBツリー全体をロックする必要があるため、答えは「仕方がない」と思います。O(log N)のパフォーマンスを得るには、各ノードのリーフカウントに依存します。ルートへのパスにあるこれらすべてのカウントは、編集するたびに変更する必要があります。したがって、ロック。このようなロックは、PostgreSQLおよびおそらくマルチユーザーデータベースの設計原則に反します。
したがって、PostgreSQLで問題を解決できない場合は、これを確認することがこの質問の次善の結果です。