2016-10-18 13 views
6

Oracle 11gから12cへの移行後、次のselect文などで大きなパフォーマンスの問題が発生します。同じ声明が11gでもうまくいきます。パフォーマンスの悪いOracle 12cでの副選択

表と索引

-- Create table 
create table PS_CS_ADRART_TB 
(
    cs_adressmandant VARCHAR2(5) not null, 
    cs_person_id  VARCHAR2(20) not null, 
    cs_beziehung_id VARCHAR2(20) not null, 
    seqnum    INTEGER not null, 
    effdt    DATE, 
    eff_status   VARCHAR2(1) not null, 
    cs_adrart_cd  VARCHAR2(20) not null, 
    cs_adress_id  VARCHAR2(20) not null, 
    cs_kdnr_as400  VARCHAR2(8) not null, 
    cs_plzgk   VARCHAR2(11) not null, 
    cs_plz_pf   VARCHAR2(15) not null, 
    cs_aendgr_cd  VARCHAR2(20) not null, 
    cs_datasource_cd VARCHAR2(20) not null, 
    cs_betrag   NUMBER(14,4) not null, 
    cs_belegdat  DATE, 
    cs_adrtyp_xl  VARCHAR2(2) not null, 
    cs_checked   VARCHAR2(1) not null, 
    cs_journal_xl  VARCHAR2(4) not null, 
    address2   VARCHAR2(55) not null, 
    row_added_dttm  TIMESTAMP(6), 
    row_added_oprid VARCHAR2(30) not null, 
    row_lastmant_dttm TIMESTAMP(6), 
    row_lastmant_oprid VARCHAR2(30) not null, 
    cs_recstat_xl  VARCHAR2(4) not null, 
    cs_update_count NUMBER(10) not null 
) 
tablespace CS_APP 
    pctfree 10 
    initrans 1 
    maxtrans 255 
    storage 
    (
    initial 102416K 
    next 1M 
    minextents 1 
    maxextents unlimited 
); 
-- Create/Recreate indexes 
create unique index PSACS_ADRART_TB on PS_CS_ADRART_TB (CS_ADRESSMANDANT, CS_KDNR_AS400, EFFDT) 
    tablespace PSINDEX 
    pctfree 10 
    initrans 2 
    maxtrans 255 
    storage 
    (
    initial 20M 
    next 1M 
    minextents 1 
    maxextents unlimited 
); 
create index PSBCS_ADRART_TB on PS_CS_ADRART_TB (CS_PERSON_ID) 
    tablespace PSINDEX 
    pctfree 10 
    initrans 2 
    maxtrans 255 
    storage 
    (
    initial 20M 
    next 1M 
    minextents 1 
    maxextents unlimited 
); 
create index PSCCS_ADRART_TB on PS_CS_ADRART_TB (CS_BEZIEHUNG_ID) 
    tablespace PSINDEX 
    pctfree 10 
    initrans 2 
    maxtrans 255 
    storage 
    (
    initial 20M 
    next 1M 
    minextents 1 
    maxextents unlimited 
); 
create unique index PS_CS_ADRART_TB on PS_CS_ADRART_TB (CS_ADRESSMANDANT, CS_PERSON_ID, CS_BEZIEHUNG_ID, SEQNUM, EFFDT) 
    tablespace PSINDEX 
    pctfree 10 
    initrans 2 
    maxtrans 255 
    storage 
    (
    initial 20M 
    next 1M 
    minextents 1 
    maxextents unlimited 
); 
create index PSDCS_ADRART_TB on PS_CS_ADRART_TB (CS_PLZ_PF) 
    tablespace PSINDEX 
    pctfree 10 
    initrans 2 
    maxtrans 255 
    storage 
    (
    initial 40K 
    next 1M 
    minextents 1 
    maxextents unlimited 
); 
create index PS0CS_ADRART_TB on PS_CS_ADRART_TB (CS_ADRESS_ID, CS_ADRESSMANDANT, CS_PERSON_ID, CS_BEZIEHUNG_ID, SEQNUM, EFFDT) 
    tablespace PSINDEX 
    pctfree 10 
    initrans 2 
    maxtrans 255 
    storage 
    (
    initial 20M 
    next 1M 
    minextents 1 
    maxextents unlimited 
); 
create index PS1CS_ADRART_TB on PS_CS_ADRART_TB (CS_KDNR_AS400, CS_ADRESSMANDANT, CS_PERSON_ID, CS_BEZIEHUNG_ID, SEQNUM, EFFDT) 
    tablespace PSINDEX 
    pctfree 10 
    initrans 2 
    maxtrans 255 
    storage 
    (
    initial 20M 
    next 1M 
    minextents 1 
    maxextents unlimited 
); 
create index PS2CS_ADRART_TB on PS_CS_ADRART_TB (ROW_ADDED_DTTM, CS_ADRESSMANDANT, CS_PERSON_ID, CS_BEZIEHUNG_ID, SEQNUM, EFFDT) 
    tablespace PSINDEX 
    pctfree 10 
    initrans 2 
    maxtrans 255 
    storage 
    (
    initial 40K 
    next 1M 
    minextents 1 
    maxextents unlimited 
); 
create index PS3CS_ADRART_TB on PS_CS_ADRART_TB (ROW_ADDED_OPRID, CS_ADRESSMANDANT, CS_PERSON_ID, CS_BEZIEHUNG_ID, SEQNUM, EFFDT) 
    tablespace PSINDEX 
    pctfree 10 
    initrans 2 
    maxtrans 255 
    storage 
    (
    initial 40K 
    next 1M 
    minextents 1 
    maxextents unlimited 
); 
create index PS4CS_ADRART_TB on PS_CS_ADRART_TB (ROW_LASTMANT_DTTM, CS_ADRESSMANDANT, CS_PERSON_ID, CS_BEZIEHUNG_ID, SEQNUM, EFFDT) 
    tablespace PSINDEX 
    pctfree 10 
    initrans 2 
    maxtrans 255 
    storage 
    (
    initial 40K 
    next 1M 
    minextents 1 
    maxextents unlimited 
); 
create index PS5CS_ADRART_TB on PS_CS_ADRART_TB (ROW_LASTMANT_OPRID, CS_ADRESSMANDANT, CS_PERSON_ID, CS_BEZIEHUNG_ID, SEQNUM, EFFDT) 
    tablespace PSINDEX 
    pctfree 10 
    initrans 2 
    maxtrans 255 
    storage 
    (
    initial 40K 
    next 1M 
    minextents 1 
    maxextents unlimited 
); 
create index PS6CS_ADRART_TB on PS_CS_ADRART_TB (CS_RECSTAT_XL, CS_ADRESSMANDANT, CS_PERSON_ID, CS_BEZIEHUNG_ID, SEQNUM, EFFDT) 
    tablespace PSINDEX 
    pctfree 10 
    initrans 2 
    maxtrans 255 
    storage 
    (
    initial 40K 
    next 1M 
    minextents 1 
    maxextents unlimited 
); 

テーブルサイズ

select count(*) from ps_cs_adrart_tb a 
--> 41367270 

Selectステートメント

SELECT A.CS_ADRESS_ID, A.SEQNUM, TO_CHAR(A.EFFDT, 'YYYY-MM-DD') 
     from PS_CS_ADRART_TB A 
    where A.CS_ADRESSMANDANT = '001' 
     and a.cs_kdnr_as400 = '63916917' 
     and a.effdt = 
      (select max(b.effdt) 
       from ps_cs_adrart_tb b 
      where b.cs_adressmandant = a.cs_adressmandant 
       and b.cs_person_id = a.cs_person_id 
       and b.cs_beziehung_id = a.cs_beziehung_id 
       and b.seqnum = a.seqnum 
       and b.effdt <= trunc(sysdate) 
       ) 

あなたが見ることができるようにデータをフィルタリングするために使用されているインデックスPS_CS_ADRART_TBのみCS_ADRESSMANDANTEFFDTから、計画のOracle 12cの

------------------------------------------------------------------------------------------------------------ 
    | Id | Operation        | Name   | Rows  | Bytes  | Cost | Time  | 
    ------------------------------------------------------------------------------------------------------------ 
    | 0 | SELECT STATEMENT      |     |  1 |  140 | 34366 | 00:00:02 | 
    | * 1 | HASH JOIN       |     |  1 |  140 | 34366 | 00:00:02 | 
    | 2 | TABLE ACCESS BY INDEX ROWID BATCHED | PS_CS_ADRART_TB |  1 |  89 |  1 | 00:00:01 | 
    | * 3 |  INDEX RANGE SCAN     | PS1CS_ADRART_TB |  1 |   |  1 | 00:00:01 | 
    | 4 | VIEW        | VW_SQ_1   | 41889 | 2136339 | 34365 | 00:00:02 | 
    | * 5 |  FILTER        |     |   |   |  |   | 
    | 6 |  HASH GROUP BY      |     | 41889 | 2471451 | 34365 | 00:00:02 | 
    | * 7 |  INDEX RANGE SCAN     | PS_CS_ADRART_TB | 12746381 | 752036479 | 34365 | 00:00:02 | 
    ------------------------------------------------------------------------------------------------------------ 

    Predicate Information (identified by operation id): 
    ------------------------------------------ 
    * 1 - access("A"."EFFDT"="MAX(B.EFFDT)" AND "ITEM_1"="A"."CS_ADRESSMANDANT" AND "ITEM_2"="A"."CS_PERSON_ID" AND "ITEM_3"="A"."CS_BEZIEHUNG_ID" AND "ITEM_4"="A"."SEQNUM") 
    * 3 - access("A"."CS_KDNR_AS400"='63916917' AND "A"."CS_ADRESSMANDANT"='001') 
    * 5 - filter('001'='001') 
    * 7 - access("B"."CS_ADRESSMANDANT"='001' AND "B"."EFFDT"<=TRUNC([email protected]!)) 
    * 7 - filter("B"."EFFDT"<=TRUNC([email protected]!)) 


    Note 
    ----- 
    - dynamic sampling used for this statement     

を説明

-------------------------------------------------------------------------------------------- 
    | Id | Operation      | Name   | Rows | Bytes | Cost | Time  | 
    -------------------------------------------------------------------------------------------- 
    | 0 | SELECT STATEMENT    |     | 1 | 89 | 2 | 00:00:01 | 
    | * 1 | FILTER      |     |  |  |  |   | 
    | 2 | TABLE ACCESS BY INDEX ROWID | PS_CS_ADRART_TB | 1 | 89 | 1 | 00:00:01 | 
    | * 3 |  INDEX RANGE SCAN   | PSACS_ADRART_TB | 1 |  | 1 | 00:00:01 | 
    | 4 | SORT AGGREGATE    |     | 1 | 59 |  |   | 
    | 5 |  FIRST ROW     |     | 1 | 59 | 1 | 00:00:01 | 
    | * 6 |  INDEX RANGE SCAN (MIN/MAX) | PS_CS_ADRART_TB | 1 | 59 | 1 | 00:00:01 | 
    -------------------------------------------------------------------------------------------- 

    Predicate Information (identified by operation id): 
    ------------------------------------------ 
    * 1 - filter("A"."EFFDT"= (SELECT MAX("B"."EFFDT") FROM "PS_CS_ADRART_TB" "B" WHERE "B"."EFFDT"<=TRUNC([email protected]!) AND "B"."SEQNUM"=:B1 AND "B"."CS_BEZIEHUNG_ID"=:B2 AND "B"."CS_PERSON_ID"=:B3 AND 
     "B"."CS_ADRESSMANDANT"=:B4)) 
    * 3 - access("A"."CS_ADRESSMANDANT"='001' AND "A"."CS_KDNR_AS400"='63916917') 
    * 6 - access("B"."CS_ADRESSMANDANT"=:B1 AND "B"."CS_PERSON_ID"=:B2 AND "B"."CS_BEZIEHUNG_ID"=:B3 AND "B"."SEQNUM"=:B4 AND "B"."EFFDT"<=TRUNC([email protected]!))  

計画Oracle 11gのを説明し、それは非常に悪いです。

次のわずかに異なるSELECT文を使用すると、索引はOracle 12cでサブSELECTのデータを決定するために使用されます。外側の条件が

min()代わりの副選択で max()

SELECT A.CS_ADRESS_ID, A.SEQNUM, TO_CHAR(A.EFFDT, 'YYYY-MM-DD'), a.cs_person_id 
     from PS_CS_ADRART_TB A 
    where a.cs_kdnr_as400 = '63916917' and a.cs_adressmandant = '001' 
     and a.effdt = 
      (select min(b.effdt) 
       from ps_cs_adrart_tb b 
      where b.cs_adressmandant = a.cs_adressmandant 
       and b.cs_person_id = a.cs_person_id 
       and b.cs_beziehung_id = a.cs_beziehung_id 
       and b.seqnum = a.seqnum 
       and b.effdt <= sysdate 
       ); 

    --------------------------------------------------------------------------------------------------- 
    | Id | Operation        | Name   | Rows | Bytes | Cost | Time  | 
    --------------------------------------------------------------------------------------------------- 
    | 0 | SELECT STATEMENT      |     | 1 | 109 | 2 | 00:00:01 | 
    | 1 | NESTED LOOPS       |     | 1 | 109 | 2 | 00:00:01 | 
    | 2 | TABLE ACCESS BY INDEX ROWID BATCHED | PS_CS_ADRART_TB | 1 | 89 | 1 | 00:00:01 | 
    | * 3 |  INDEX RANGE SCAN     | PS1CS_ADRART_TB | 1 |  | 1 | 00:00:01 | 
    | * 4 | VIEW PUSHED PREDICATE    | VW_SQ_1   | 1 | 20 | 1 | 00:00:01 | 
    | 5 |  SORT GROUP BY      |     | 1 | 59 | 1 | 00:00:01 | 
    | * 6 |  INDEX RANGE SCAN     | PS_CS_ADRART_TB | 1 | 59 | 1 | 00:00:01 | 
    --------------------------------------------------------------------------------------------------- 

    Predicate Information (identified by operation id): 
    ------------------------------------------ 
    * 3 - access("A"."CS_KDNR_AS400"='63916917' AND "A"."CS_ADRESSMANDANT"='001') 
    * 4 - filter("A"."EFFDT"="MIN(B.EFFDT)" AND "ITEM_1"="A"."CS_ADRESSMANDANT") 
    * 6 - access("B"."CS_ADRESSMANDANT"='001' AND "B"."CS_PERSON_ID"="A"."CS_PERSON_ID" AND "B"."CS_BEZIEHUNG_ID"="A"."CS_BEZIEHUNG_ID" AND "B"."SEQNUM"="A"."SEQNUM" AND "B"."EFFDT"<[email protected]!) 


    Note 
    ----- 
    - dynamic sampling used for this statement 

(上記のように)インデックスを再構築し、

によって統計更新を使用
SELECT A.CS_ADRESS_ID, A.SEQNUM, TO_CHAR(A.EFFDT, 'YYYY-MM-DD') 
    from PS_CS_ADRART_TB A 
    where a.cs_kdnr_as400 = '53916917' -- without CS_ADRESSMANDANT condition 
    and a.effdt = 
     (select max(b.effdt) 
      from ps_cs_adrart_tb b 
      where b.cs_adressmandant = a.cs_adressmandant and 
       b.cs_person_id = a.cs_person_id 
      and b.cs_beziehung_id = a.cs_beziehung_id 
      and b.seqnum = a.seqnum 
      and b.effdt <= trunc(sysdate) 
      ) 

    -------------------------------------------------------------------------------------------------- 
    | Id | Operation        | Name   | Rows | Bytes | Cost | Time  | 
    -------------------------------------------------------------------------------------------------- 
    | 0 | SELECT STATEMENT      |     | 1 | 89 | 2 | 00:00:01 | 
    | 1 | TABLE ACCESS BY INDEX ROWID BATCHED | PS_CS_ADRART_TB | 1 | 89 | 1 | 00:00:01 | 
    | * 2 | INDEX RANGE SCAN     | PS1CS_ADRART_TB | 1 |  | 1 | 00:00:01 | 
    | 3 |  SORT AGGREGATE     |     | 1 | 59 |  |   | 
    | 4 |  FIRST ROW      |     | 1 | 59 | 1 | 00:00:01 | 
    | * 5 |  INDEX RANGE SCAN (MIN/MAX)  | PS_CS_ADRART_TB | 1 | 59 | 1 | 00:00:01 | 
    -------------------------------------------------------------------------------------------------- 

    Predicate Information (identified by operation id): 
    ------------------------------------------ 
    * 2 - access("A"."CS_KDNR_AS400"='53916917') 
    * 2 - filter("A"."EFFDT"= (SELECT MAX("B"."EFFDT") FROM "PS_CS_ADRART_TB" "B" WHERE "B"."EFFDT"<=TRUNC([email protected]!) AND "B"."SEQNUM"=:B1 AND "B"."CS_BEZIEHUNG_ID"=:B2 AND "B"."CS_PERSON_ID"=:B3 AND 
     "B"."CS_ADRESSMANDANT"=:B4)) 
    * 5 - access("B"."CS_ADRESSMANDANT"=:B1 AND "B"."CS_PERSON_ID"=:B2 AND "B"."CS_BEZIEHUNG_ID"=:B3 AND "B"."SEQNUM"=:B4 AND "B"."EFFDT"<=TRUNC([email protected]!)) 


    Note 
    ----- 
    - dynamic sampling used for this statement 

を選択する場合

を変更します

EXEC DBMS_STATS.delete_table_stats('SYSADM', 'PS_CS_ADRART_TB'); -- EXEC DBMS_STATS.gather_table_stats('SYSADM', 'PS_CS_ADRART_TB'); EXEC DBMS_STATS.gather_table_stats(ownname => 'SYSADM', tabname => 'PS_CS_ADRART_TB', cascade => true); 

は役に立ちません。

ここでは何が起こっていますか?いかなるアドバイスも高く評価されます。前もって感謝します。

+1

でそれを試すことができます。 –

+2

質問は明確で、よくタグ付けされ、必要な構造を構築するためのすべてのステートメントを含み、テーブルのサイズに関する情報を提供し、多くの試みと各ステートメントの計画を含んでいます... +1 – Aleksej

+1

12Cプランでこのステートメントに使用されている*動的サンプリングは、 'gather_table_stats()'にもかかわらず統計が最新ではないことを示しているようです。 'cascade => true'で' gather_table_stats() 'を実行しますか?(明らかに、SYSADMは本当にそれらのテーブルの_owner_ですか?) –

答えて

1

を除外するために、問合せをリライトしてみてください。

あなたがダウン質問を投票なぜ私に知らせてください

alter session set "_unnest_subquery" = FALSE; 
+0

それだけです! Oracleサポートでは、隠しパラメータ_unnest_subqueryをFALSEに設定して、Oracleデータベース上のPeopleSoftアプリケーションのパフォーマンスを向上させることをお勧めします。これはhttp://www.bobbydurrettdba.com/2012/11/07/_unnest_subqueryfalse-for-peoplesoft-performance/に記載されているのと同じ動作です –

0

フランク。私が理解しているように、cs_person_idとcs_beziehung_idによって最後の1行を取得したい場合は、b.effdtは今日よりも低いか等しい。まず、選択性に関する情報を統計情報として収集することができます。それはCBOの選択を助ける。

BEGIN 
dbms_stats.Gather_table_stats('SYSADM', 'PS_CS_ADRART_TB', 
method_opt => 'FOR COLUMNS SIZE 254 CS_KDNR_AS400 CS_ADRESSMANDANT'); 
END; 
/

私は何を見つけるかと思います。あなたは多くのインデックスを持っているので、魔法はユニークなものとして作成されるかもしれません。すでに一意索引列が含まれています。

create unique index PS1CS_ADRART_TB on PS_CS_ADRART_TB (CS_KDNR_AS400, CS_ADRESSMANDANT, CS_PERSON_ID, CS_BEZIEHUNG_ID, SEQNUM, EFFDT) ; 
create unique index PS0CS_ADRART_TB on PS_CS_ADRART_TB (CS_ADRESS_ID, CS_ADRESSMANDANT, CS_PERSON_ID, CS_BEZIEHUNG_ID, SEQNUM, EFFDT); 
create unique index PS1CS_ADRART_TB on PS_CS_ADRART_TB (CS_KDNR_AS400, CS_ADRESSMANDANT, CS_PERSON_ID, CS_BEZIEHUNG_ID, SEQNUM, EFFDT); 
create unique index PS2CS_ADRART_TB on PS_CS_ADRART_TB (ROW_ADDED_DTTM, CS_ADRESSMANDANT, CS_PERSON_ID, CS_BEZIEHUNG_ID, SEQNUM, EFFDT); 
create unique index PS3CS_ADRART_TB on PS_CS_ADRART_TB (ROW_ADDED_OPRID, CS_ADRESSMANDANT, CS_PERSON_ID, CS_BEZIEHUNG_ID, SEQNUM, EFFDT); 
create unique index PS4CS_ADRART_TB on PS_CS_ADRART_TB (ROW_LASTMANT_DTTM, CS_ADRESSMANDANT, CS_PERSON_ID, CS_BEZIEHUNG_ID, SEQNUM, EFFDT); 
create unique index PS5CS_ADRART_TB on PS_CS_ADRART_TB (ROW_LASTMANT_OPRID, CS_ADRESSMANDANT, CS_PERSON_ID, CS_BEZIEHUNG_ID, SEQNUM, EFFDT); 
create unique index PS6CS_ADRART_TB on PS_CS_ADRART_TB (CS_RECSTAT_XL, CS_ADRESSMANDANT, CS_PERSON_ID, CS_BEZIEHUNG_ID, SEQNUM, EFFDT); 

そして最後に、私はあなたがFALSEにパラメータ_unnest_subqueryを設定すべきだと思うサブクエリ

SELECT cs_adress_id,seqnum, effdt_chr 
FROM (SELECT /* */ a.cs_adress_id 
      ,a.seqnum 
      ,to_char(a.effdt, 'YYYY-MM-DD') AS effdt_chr 
      ,dense_rank() over(PARTITION BY a.cs_adressmandant, a.cs_person_id 
             , a.cs_beziehung_id, a.seqnum 
           ORDER BY a.effdt DESC) AS rnk 
    FROM ps_cs_adrart_tb a 
    WHERE a.cs_adressmandant = '001' 
     AND a.cs_kdnr_as400 = '63916917' 
     AND a.effdt <= trunc(sysdate) 
) 
WHERE rnk = 1; 
+0

はい、このステートメントは、指定された人物の現在のデータを選択します。 EXPLAIN計画の統計値は最新です(CS_ADRESSMANDANT = 001の場合は12746381行、EFFDT = sysdateの場合は適切な値)ので、この索引のCS_PERSON_ID、CS_BEZIEHUNG_IDおよびSEQNUMの別のフィールドは使用されません。また、選択されたステートメントやインデックスを変更することもできますが、アプリケーションの変更を最小限に抑えて、副作用による労力とリスクを回避しています。 –

+0

それでも 'method_opt => 'FOR COLUMNS SIZE 254 CS_KDNR_AS400 CS_ADRESSMANDANT''で試しましたが、成功しませんでした。 –

+0

hash_group_byの問題のように見えます。ヒント '/ * + opt_param( '_ optimizer_aggr_groupby_elim'、 'true')* /'を使用してプランのクエリを確認してください。 –

関連する問題