从Oracle 11g迁移到12c之后,我们遇到了一个巨大的性能问题,例如使用以下select语句.同样的声明在11g中运行良好.
表和索引
-- 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,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,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,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,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,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,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,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 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) )
解释计划Oracle 11g
-------------------------------------------------------------------------------------------- | 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(SYSDATE@!) 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(SYSDATE@!))
解释计划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(SYSDATE@!)) * 7 - filter("B"."EFFDT"<=Trunc(SYSDATE@!)) Note ----- - dynamic sampling used for this statement
如您所见,从索引PS_CS_ADRART_TB只有CS_ADRESSMANDANT和EFFDT用于过滤数据,这是非常糟糕的.
使用以下略有不同的select语句,Oracle 12c将按预期使用索引来确定subselect的数据.
改变外部选择的条件
SELECT A.CS_ADRESS_ID,'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(SYSDATE@!) 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(SYSDATE@!)) Note ----- - dynamic sampling used for this statement
在subselect中使用min()而不是max()
SELECT A.CS_ADRESS_ID,'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"<=SYSDATE@!) 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 );
没有帮助.
这里发生了什么?任何建议都非常感谢.提前致谢.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。