1

各行にランダムに生成された主キー、メッセージ、およびユーザーが含まれるDBテーブルがあります。各ユーザーには約10〜100のメッセージがありますが、1万〜5万のユーザーがいます。

私は一度に各ユーザーのために毎日メッセージを書きます。テーブルをできるだけ小さくするために、新しいメッセージを作成する前に、各ユーザーの古いメッセージを破棄したいと思います。

今、私はこれを効果的に行っています:

delete from table where user='mk'

次に、そのユーザーへのすべてのメッセージを書き込みます。同時に多くのスレッドがこれを実行しているため、多くの競合が発生しています。

各ユーザーの最新のメッセージセットを保持するための追加の要件があります。

DBに直接アクセスできません。私はいくつかの中古のフィードバックに基づいて問題を推測しようとしています。私がこのシナリオに焦点を当てている理由は、削除クエリが(私の知る限りでは)多くの待機時間を示していることに加えて、新しく追加された機能であるためです。

誰かアドバイスはありますか?

次の方が良いでしょうか:

select key from table where user='mk'

次に、そこから個々の行を削除しますか?私はそれがより残酷なロックにつながるかもしれないと思っています。

4

7 に答える 7

4

これをすべてのユーザーに対して毎日行う場合は、1つのステートメントでテーブルからすべてのレコードを削除してみませんか?あるいは

truncate table whatever reuse storage
/

編集

このアプローチを提案する理由は、プロセスが、古いメッセージを消去する前に、ユーザーメッセージを毎日バッチアップロードするように見えるためです。つまり、ビジネスルールは、「特定のユーザーに対して1日分のメッセージのみをテーブルに保持する」というもののように思えます。このプロセスがすべてのユーザーに対して実行される場合、単一の操作が最も効率的です。

ただし、ユーザーが毎日新しいメッセージセットを取得せず、ユーザーごと最新のメッセージセットを保持することを要求する補助ルールがある場合、テーブル全体をザッピングすることは誤りです。

于 2009-10-30T12:36:41.113 に答える
3

いいえ、一連の「行ごと」(またはトム・カイトが「遅い」と呼ぶもの)操作よりも、一連の行に対して単一のSQLステートメントを実行する方が常に優れています。あなたが「多くの論争を見ている」と言うとき、あなたは正確に何を見ていますか?明らかな質問:列USERはインデックス付けされていますか?

(もちろん、列名は予約語であるため、Oracleデータベースでは実際にはUSERにすることはできません!)

編集:列USERはインデックス付けされていないとおっしゃいました。つまり、各削除には、最大50K * 100 = 500万行(または最大で10K * 10 = 100,000行)の全表スキャンが含まれ、わずか10-100行が削除されます。USERにインデックスを追加すると、問題が解決する場合があります。

于 2009-10-30T12:34:36.513 に答える
0

あなたのDBAに話しかける

彼はあなたを助けるためにそこにいます。私たちDBAがこのような何かのために開発者からアクセスを奪うとき、私たちはそのタスクのためにあなたにサポートを提供すると想定されます。コードの完了に時間がかかりすぎて、その時間がデータベースに拘束されているように見える場合、DBAは何が起こっているかを正確に調べて提案を提供したり、場合によっては何も変更せずに問題を解決したりすることができます。

問題の説明を一瞥するだけで、競合の問題を見ているようには見えませんが、基本的な構造については何も知りません。

本当に、DBAに相談してください。彼はおそらく、最新のCPU展開を計画する代わりに、何か楽しいものを見るのを楽しむでしょう。

于 2009-10-30T14:45:39.387 に答える
0

ロックの競合が発生していることを確認しますか?同時(ただし無関係な更新)が多すぎるために、ディスクの競合が発生している可能性が高くなります。これに対する解決策は、使用しているスレッドの数を減らすことです。ディスクの競合が少ないほど、合計スループットが高くなります。

于 2009-10-30T12:34:41.257 に答える
0

要件をもう少し明確に定義する必要があると思います...

例えば。メッセージを書き込みたいすべてのユーザーがわかっている場合は、IDを一時テーブルに挿入し、IDにインデックスを付けて、バッチ削除します。次に、起動しているスレッドは2つのことを実行しています。ユーザーのIDを一時テーブルに書き込み、メッセージを別の一時テーブルに書き込みます。次に、スレッドの実行が終了すると、メインスレッドは

DELETE*FROMメッセージINNERJOINTEMP_MEMBERS ON ID = TEMP_ID

INSERT INTO MESSAGES SELECT * FROM TEMP_messges

私はOracleの構文に精通していませんが、ユーザーのメッセージがすべてすばやく連続して行われる場合は、それが私がそれにアプローチする方法です。

お役に立てれば

于 2009-10-30T13:35:14.753 に答える
-2

これは物事をスピードアップするかもしれません:

ルックアップテーブルを作成します。

create table rowid_table (row_id ROWID ,user VARCHAR2(100));
create index rowid_table_ix1 on rowid_table (user);

毎晩仕事をする:

truncate table rowid_table;
insert /*+ append */ into rowid_table
select ROWID row_id , user
from table;
dbms_stats.gather_table_stats('SCHEMAOWNER','ROWID_TABLE');

次に、レコードを削除する場合:

delete from table
where ROWID IN (select row_id
                from rowid_table
                where user = 'mk');
于 2009-10-30T15:19:14.967 に答える
-4

あなた自身の提案は非常に賢明なようです。小さなバッチでロックすることには、2つの利点があります。

  • トランザクションは小さくなります
  • ロックは一度に数行に制限されます

バッチでのロックは大きな改善になるはずです。

于 2009-10-30T12:37:23.623 に答える