0

たとえば、Oracleデータベースにmy_tableと呼ばれるテーブルがあります。ログテーブルの一種です。これには、「id」という名前の増分列と、登録ユーザーに固有の「registration_number」があります。今、登録ユーザーの最新の変更を取得したいので、このタスクを達成するために以下のクエリを書きました:

最初のバージョン:

SELECT t.*
FROM my_table t
WHERE t.id =
  (SELECT MAX(id) FROM my_table t_m WHERE t_m.registration_number = t.registration_number
  );

2 番目のバージョン:

SELECT t.*
FROM my_table t
INNER JOIN
  ( SELECT MAX(id) m_id FROM my_table GROUP BY registration_number
  ) t_m
ON t.id = t_m.m_id;

私の最初の質問は、上記のどのクエリが推奨されているのか、そしてその理由は何ですか? 2 つ目は、このテーブルに約 70.000 の挿入が行われる場合がありますが、ほとんどの場合、挿入される行の数は 0 から 2000 の間で変化します。このテーブルにインデックスを追加するのは合理的ですか?

4

3 に答える 3

2

より高速なクエリを確認するには、実行計画とコストを確認する必要があります。これにより、公正なアイデアが得られます。しかし、分析によりクエリの実行がはるかに高速になるため、Ed Gibbs のソリューションに同意します。このテーブルが非常に大きくなると思われる場合は、テーブルを分割してローカル インデックスを使用することをお勧めします。それらは間違いなく、より高速なクエリを作成するのに役立ちます。

多数の行を挿入したい場合は、各挿入インデックスも更新する必要があるため、インデックスの挿入が遅くなります [ID のインデックスはお勧めしません]。これについて私が考えている2つの解決策があります:

  1. 挿入前にインデックスを削除し、挿入後に再作成できます。
  2. 逆キー インデックスを使用します。このリンクを確認してください: http://oracletoday.blogspot.in/2006/09/there-is-option-to-create-index.html . 逆キー インデックスはクエリに少し影響を与える可能性があるため、トレードオフがあります。
于 2013-04-24T07:18:24.173 に答える
2

分析クエリは、各登録ユーザーの最新の変更を取得する最速の方法である可能性があります。

SELECT registration_number, id
FROM (
  SELECT
    registration_number,
    id,
    ROW_NUMBER() OVER (PARTITION BY registration_number ORDER BY id DESC) AS IDRankByUser
  FROM my_table
)
WHERE IDRankByUser = 1

インデックスについては、既にregistration_number. 追加のインデックスidはクエリに役立ちますが、インデックスを正当化するほどではなく、十分ではないかもしれません。一度に 70K 行を挿入すると、追加のインデックスによって速度が低下するためINSERTです。インデックスに価値があるかどうかを判断するには、実験 (および実行計画の確認) を行う必要があります。

于 2013-04-24T05:42:39.710 に答える
0

より高速なソリューションを探していて、各ユーザーの最後のアクティビティのリストを維持する必要がある場合、最も堅牢なソリューションは、一意のregistration_number値を持つ個別のテーブルとrowid、ログ テーブルに作成された最後のレコードを維持することです。

例 (デモのみ、構文の有効性をチェックせず、シーケンスとトリガーを省略):

create table my_log(id number not null, registration_number number, action_id varchar2(100))
/

create table last_user_action(refgistration_number number not null, last_action rowid)
/

alter table last_user_action 
  add constraint pk_last_user_action primary key (registration_number) using index 
/

create or replace procedure write_log(p_reg_num number, p_action_id varchar2)
is
  v_row_id rowid;
begin

  insert into my_log(registration_number, action_id) 
  values(p_reg_num, p_action_id)
  returning rowid into v_row_id;

  update last_user_action 
  set last_action = v_row_id 
  where registration_number = p_reg_num;

end;
/

このようなスキーマを使用すると、すべてのユーザーの最後のアクションを簡単にクエリして、パフォーマンスを向上させることができます。

select 
from
  last_user_action lua,
  my_log           l
where
  l.rowid (+) = lua.last_action

Rowid は、ストレージ ブロックを直接アドレス指定する物理ストレージ ID であり、別のサーバーに移動したり、バックアップから復元したりした後は使用できidませmy_loglast_user_action。要件。

于 2013-04-24T16:27:25.600 に答える