7

そのため、非常に大きなテーブルをいくつかクエリしています。これらが非常に大きい理由は、既存のレコードを更新するのではなく、一部のデータに変更が加えられるたびに、PeopleSoft が新しいレコードを挿入するためです。実際、そのトランザクション テーブルはデータ ウェアハウスでもあります。

これにより、最新/現在の行を取得するために、選択がネストされたクエリが必要になります。それらは両方とも有効な日付であり、各日付 (日にキャスト) 内で有効なシーケンスを持つことができます。したがって、 の現在のレコードを取得するには、次のようにするuser_id=123必要があります。

select * from sometable st
where st.user_id = 123
and st.effective_date = (select max(sti.effective_date) 
  from sometable sti where sti.user_id = st.user_id)
and st.effective_sequence = (select max(sti.effective_sequence) 
  from sometable sti where sti.user_id = st.user_id
  and sti.effective_date = st.effective_date)

これらのテーブルには驚異的な数のインデックスがあり、クエリを高速化するものは他に見つかりません。

私の問題は、おそらく 50 個の user_id について、これらのテーブルから個人に関するデータを取得したいことがよくありますが、レコードが数個しかないテーブルをこれらの PeopleSoft テーブルのいくつかと結合すると、うまくいかないことです。

PeopleSoft テーブルは、データベース リンクを介してアクセスするリモート データベース上にあります。私のクエリは次のようになります。

select st.* from local_table lt, sometable@remotedb st
where lt.user_id in ('123', '456', '789')
and lt.user_id = st.user_id
and st.effective_date = (select max(sti.effective_date) 
  from sometable@remotedb sti where sti.user_id = st.user_id)
and st.effective_sequence = (select max(sti.effective_sequence) 
  from sometable@remotedb sti where sti.user_id = st.user_id
  and sti.effective_date = st.effective_date)

複数の PeopleSoft テーブルをローカル テーブルに結合する必要があると、事態はさらに悪化します。パフォーマンスは受け入れられません。

パフォーマンスを向上させるためにできることは何ですか? ローカル テーブルが最初に PeopleSoft のパートナーに結合されるようにクエリ ヒントを試しました。そのため、正しい user_id に絞り込む前にすべてのテーブルを結合しようとしません。私はLEADINGヒントを試し、処理をリモートデータベースにプッシュしようとするヒントをいじりましたが、説明計画がわかりにくく、いくつかの操作で「REMOTE」とだけ言われ、何が起こっているのかわかりませんでした。

PeopleSoft とテーブルの場所を変更する権限がないと仮定すると、ヒントは最良の選択でしょうか? ローカル テーブルを 4 つのリモート テーブルと結合していて、ローカル テーブルがそのうちの 2 つと結合している場合、ローカル テーブル (非常に小さい - 実際、インライン ビューを実行するだけでよい) になるようにヒントをフォーマットするにはどうすればよいでしょうか。ローカルテーブルを興味のある user_ids だけにするために) 最初に各リモートテーブルと結合しますか?

編集:アプリケーションはリアルタイム データを必要とするため、残念ながらマテリアライズド ビューやその他のデータ キャッシュ方法では十分ではありません。

4

10 に答える 10

4

1 つのアプローチは、すべてに PL/SQL 関数を貼り付けることです。例として

create table remote (user_id number, eff_date date, eff_seq number, value varchar2(10));

create type typ_remote as object (user_id number, eff_date date, eff_seq number, value varchar2(10));
.
/

create type typ_tab_remote as table of typ_remote;
.
/

insert into remote values (1, date '2010-01-02', 1, 'a');
insert into remote values (1, date '2010-01-02', 2, 'b');
insert into remote values (1, date '2010-01-02', 3, 'c');
insert into remote values (1, date '2010-01-03', 1, 'd');
insert into remote values (1, date '2010-01-03', 2, 'e');
insert into remote values (1, date '2010-01-03', 3, 'f');

insert into remote values (2, date '2010-01-02', 1, 'a');
insert into remote values (2, date '2010-01-02', 2, 'b');
insert into remote values (2, date '2010-01-03', 1, 'd');

create function show_remote (i_user_id_1 in number, i_user_id_2 in number) return typ_tab_remote pipelined is
    CURSOR c_1 is
    SELECT user_id, eff_date, eff_seq, value
    FROM
        (select user_id, eff_date, eff_seq, value, 
                        rank() over (partition by user_id order by eff_date desc, eff_seq desc) rnk
        from remote
        where user_id in (i_user_id_1,i_user_id_2))
    WHERE rnk = 1;
begin
    for c_rec in c_1 loop
        pipe row (typ_remote(c_rec.user_id, c_rec.eff_date, c_rec.eff_seq, c_rec.value));
    end loop;
    return;
end;
/

select * from table(show_remote(1,null));

select * from table(show_remote(1,2));

user_id をパラメーターとして個別に渡すのではなく、それらをローカル テーブル (グローバル一時テーブルなど) にロードすることができます。PL/SQL はテーブルをループし、ローカル テーブルの各行に対してリモート選択を実行します。ローカル テーブルとリモート テーブルの両方を持つ単一のクエリはありません。事実上、独自の結合コードを作成することになります。

于 2010-06-25T01:45:17.263 に答える
4

このようなクエリのリファクタリングはまったく役に立ちますか?

SELECT *
  FROM (SELECT st.*, MAX(st.effective_date) OVER (PARTITION BY st.user_id) max_dt,
                     MAX(st.effective_sequence) OVER (PARTITION BY st.user_id, st.effective_date) max_seq
          FROM local_table lt JOIN sometable@remotedb st ON (lt.user_id = st.user_id)
         WHERE lt.user_id in ('123', '456', '789'))
 WHERE effective_date = max_dt
   AND effective_seq = max_seq;

DB リンクを介したパフォーマンスの参加は本当にひどいものであり、このアプローチで達成できることは限られている可能性が高いという @Mark Ba​​ker に同意します。

于 2010-06-24T21:19:07.377 に答える
3

1 つのオプションは、最初に共通テーブル式を使用してクエリのリモート部分を具体化することです。これにより、関連するデータのみがリモート データベースからフェッチされることを確認できます。もう 1 つの改善は、リモート データベースに対する 2 つのサブクエリを 1 つの分析関数ベースのサブクエリにマージすることです。 .そのようなクエリは、現在のクエリでも使用できます。データベースで遊んだ後でのみ、他の提案を行うことができます。

下記参照

with remote_query as
(
    select /*+ materialize */  st.* from sometable@remotedb st
    where st.user_id in ('123', '456', '789')
    and st.rowid in( select first_value(rowid) over (order by effective_date desc, 
                         effective_sequence desc ) from sometable@remotedb st1 
                      where st.user_id=st1.user_id)
)

select lt.*,st.* 
FROM local_table st,remote_query rt
where st.user_id=rt.user_id
于 2010-06-24T21:21:40.627 に答える
1

データの鮮度の要件については言及していませんが、1つのオプションは、次のデータのみを含むマテリアライズドビュー(ソースシステムでスナップショットログを作成できないため、REFRESH COMPLETEに制限されます)を作成することです。トランザクションテーブルの現在のバージョン管理された行。これらのマテリアライズドビューテーブルはローカルシステムに存在し、クエリのパフォーマンスを向上させるために追加のインデックスを追加できます。

于 2010-06-24T20:22:22.193 に答える
1

パフォーマンスの問題は、リンクを介したアクセスになります。ローカル テーブルに対するクエリの一部では、すべてがローカルで実行されるため、リモート インデックスにアクセスできず、すべてのリモート データをプルして lkocally にテストします。

履歴データについて定期的 (毎晩) に peoplesoft データベースから更新されたローカル データベースで具体化されたビューを使用できる場合、今日の変更についてのみリモートの peoplesoft データベースにアクセスし (effective_date = today を where 句に追加)、 2 つのクエリ。

もう1つのオプションは、リモートデータが一時的なローカルテーブルまたはマテリアライズドビューにプルするためだけに INSERT INTO X SELECT FROM を使用し、次に2番目のクエリを使用してそれをローカルデータと結合することです... josephj1989の提案に似ています

または (ライセンスの問題があるかもしれませんが)、リモートの peoplesoft データベースを使用してローカル データベースを RAC クラスタリングしてみてください。

于 2010-06-24T20:57:09.170 に答える
0

PeopleSoftテーブルは配信されたものですか、それともカスタムですか?それは物理的なテーブルであり、PS側の不十分に記述されたビューではありませんか?対象となる配信済みレコードの場合(例はPS_JOBまたはそれを参照するビューによく似ています)、これを示すことができます。PS_JOBは、大量のインデックスが配信される獣であり、ほとんどのサイトではさらに多くのインデックスが追加されています。

テーブルのインデックスがわかっている場合は、Oracleヒントを使用して、使用する優先インデックスを指定できます。それは時々役立ちます。

問題がどこにあるかを判断できるかどうかを確認するための説明計画を実行しましたか?多分、デカルト結合、全表スキャンなどがありますか?

于 2010-06-24T23:49:55.540 に答える
0

データ ウェアハウスでタイプ 2 のディメンションを扱っているように見えます。タイプ 2 ディメンションを実装する方法はいくつかありますが、主に のような列がありますValidFrom, ValidTo, Version, Status。それらのすべてが常に存在するわけではありません。テーブルのスキーマを投稿できれば興味深いでしょう。これがどのように見えるかの例です (John Smith は 2010 年 6 月 24 日にインディアナ州からオハイオ州に引っ越しました)。

UserKey  UserBusinessKey State    ValidFrom    ValidTo   Version  Status
7234     John_Smith_17   Indiana  2005-03-20  2010-06-23    1     expired
9116     John_Smith_17   Ohio     2010-06-24  3000-01-01    2     current

行の最新バージョンを取得するには、次を使用するのが一般的です

WHERE Status = 'current'

また

WHERE ValidTo = '3000-01-01'

これには、遠い将来の定数があることに注意してください。

また

WHERE ValidTo > CURRENT_DATE

あなたの例では ValidFrom(effective_date) を使用しているように見えるのでmax()、最新の行を見つけるために検索する必要があります。スキーマを見てStatus or ValidToください。テーブルに同等のものはありますか?

于 2010-06-25T10:45:26.453 に答える
0

サブクエリを使用する代わりに、これを試すことができます。私は Oracle をあまり使用しないので、これで Oracle のパフォーマンスが向上するかどうかはわかりません。

SELECT
    ST1.col1,
    ST1.col2,
    ...
FROM
    Some_Table ST1
LEFT OUTER JOIN Some_Table ST2 ON
    ST2.user_id = ST1.user_id AND
    (
        ST2.effective_date > ST1.effective_date OR
        (
            ST2.effective_date = ST1.effective_date AND
            ST2.effective_sequence > ST1.effective_sequence
        )
    )
WHERE
    ST2.user_id IS NULL

別の可能な解決策は次のとおりです。

SELECT
    ST1.col1,
    ST1.col2,
    ...
FROM
    Some_Table ST1
WHERE
    NOT EXISTS
    (
        SELECT
        FROM
            Some_Table ST2
        WHERE
            ST2.user_id = ST1.user_id AND
            (
                ST2.effective_date > ST1.effective_date OR
                (
                    ST2.effective_date = ST1.effective_date AND
                    ST2.effective_sequence > ST1.effective_sequence
                )
            )
    )
于 2010-06-24T20:09:50.890 に答える
0

毎晩更新できる非倉庫タイプのものに使用するデータベースを作成することはオプションですか? その場合は、最新のレコードのみを移動する夜間プロセスを作成できます。これにより、毎日のクエリで行っている MAX の作業が不要になり、数またはレコードが大幅に削減されます。

また、最新のデータと利用可能なデータの間に 1 日の経過があるかどうかにもよります。

私はOracleにあまり詳しくないので、クエリを変更することで改善する方法があるかもしれません...

于 2010-06-24T20:11:49.783 に答える
0

目的の user_id を持つ行を独自のテーブルに ETL して、クエリをサポートし、クエリを実行するために必要なインデックスのみを作成できますか?

于 2010-06-24T21:46:58.020 に答える