如何改善此查询的执行时间?

时间:2014-01-26 12:10:10

标签: sql oracle join

我有一个大约有11.000.000条记录的维度,4个表在ETL过程中相互连接以填充我的维度(dimtst)。

insert into dimtst
select .... from  tdpst left outer join fhist 
left outer join dp2act
left outer join dp2cust

上面的查询持续很多(tdpst有11条记录,上面的查询大约持续15分钟),因此我创建了一个加入的临时表 tdpstfhist并将结果存储在tmpDpsInf(我创建的另一个临时表)中。

然后tmpDpsInf将与另一个具有足够执行时间的查询中的CD一起加入。

create table TMPFHIST
(
  abrnchcod NUMBER(4) not null,
  tbdptype  NUMBER(3) not null,
  cfcifno   NUMBER(8) not null,
  tdserial  NUMBER(3) not null,
  aistate   NUMBER(1)
)

--------------
create table TMPDPSINF
(
  abrnchcod     NUMBER(4) not null,
  tbdptype      NUMBER(3) not null,
  cfcifno       NUMBER(8) not null,
  tdserial      NUMBER(3) not null,
  ausrcode      NUMBER(4) not null,
  tdtitle       VARCHAR2(82),
  tdopndat      DATE,
  tdrnwdat      DATE,
  tdclsdat      DATE,
  acurrcode     CHAR(3) not null,
  abu_abrnchcod NUMBER(4) not null,
  aistate       NUMBER(1)
)
create table tdpst  
(
  abrnchcod     NUMBER(4) not null,
  tbdptype      NUMBER(3) not null,
  cfcifno       NUMBER(8) not null,
  tdserial      NUMBER(3) not null,
  ausrcode      NUMBER(4) not null,
  tdtitle       VARCHAR2(82),
  tdopndat      DATE,
  tdrnwdat      DATE,
  tdclsdat      DATE,
  acurrcode     CHAR(3) not null,
  abu_abrnchcod NUMBER(4) not null
)
--------

tmpDpsInf fills with below query:
    insert into tmpDpsInf
      select /*+parallel(12)*/
       d.ABRNCHCOD,
       d.TBDPTYPE,
       d.CFCIFNO,
       d.TDSERIAL,
       d.AUSRCODE AUSRCODE,
       d.tdtitle,
       trunc(d.tdopndat) TDOPNDAT,
       nvl(d.tdrnwdat, d.tdopndat),
       nvl(d.tdclsdat, to_date('1500/01/01', 'yyyy/mm/dd')) tdclsdat,
       d.acurrcode acurrcode,
       d.ABU_ABRNCHCOD ABU_ABRNCHCOD,
       tmp.aistate
        from tdpst  d
        left outer join fhist tmp
          on d.ABRNCHCOD = tmp.ABRNCHCOD
         and d.TBDPTYPE =  tmp.TBDPTYPE
         and d.CFCIFNO =   tmp.CFCIFNO
         and d.TDSERIAL =  tmp.TDSERIAL
       where d.TDOPNDAT <= currdate

1计划哈希值:3720425100 2
3 ------------------------------------------------- -------------------------------------------------- ----------------------- 4 | Id |操作|名称|行|字节|成本(%CPU)|时间| TQ | IN-OUT | PQ Distrib | 5 ------------------------------------------------- -------------------------------------------------- ----------------------- 6 | 0 |选择声明| | 12M | 1994M | 4248(3)| 00:01:17 | | | | 7 | 1 | PX COORDINATOR | | | | | | | | | 8 | 2 | PX SEND QC(RANDOM)| :TQ10002 | 12M | 1994M | 4248(3)| 00:01:17 | Q1,02 | P-> S | QC(兰德)| 9 | * 3 | HASH JOIN RIGHT OUTER BUFFERED | | 12M | 1994M | 4248(3)| 00:01:17 | Q1,02 | PCWP | | 10 | 4 | PX RECEIVE | | 3730K | 67M | 178(3)| 00:00:04 | Q1,02 | PCWP | | 11 | 5 | PX SEND HASH | :TQ10000 | 3730K | 67M | 178(3)| 00:00:04 | Q1,00 | P-> P |哈希| 12 | 6 | PX BLOCK ITERATOR | | 3730K | 67M | 178(3)| 00:00:04 | Q1,00 | PCWC | | 13 | 7 |表访问完全| TMPFHIST | 3730K | 67M | 178(3)| 00:00:04 | Q1,00 | PCWP | | 14 | 8 | PX RECEIVE | | 12M | 1774M | 4059(2)| 00:01:14 | Q1,02 | PCWP | | 15 | 9 | PX SEND HASH | :TQ10001 | 12M | 1774M | 4059(2)| 00:01:14 | Q1,01 | P-> P |哈希| 16 | 10 | PX BLOCK ITERATOR | | 12M | 1774M | 4059(2)| 00:01:14 | Q1,01 | PCWC | | 17 | * 11 |表访问完全| TDPST | 12M | 1774M | 4059(2)| 00:01:14 | Q1,01 | PCWP | | 18 ------------------------------------------------- -------------------------------------------------- ----------------------- 19个
20谓词信息(由操作ID标识): 21 ------------------------------------------------- - 22个
23 3 - 访问(&#34; D&#34;。&#34; TDSERIAL&#34; =&#34; TMP&#34;。&#34; TDSERIAL&#34;(+)AND&#34; D&# 34;。&#34; CFCIFNO&#34; =&#34; TMP&#34;。&#34; CFCIFNO&#34;(+)AND 24&#34; D&#34;。&#34; TBDPTYPE&#34; =&#34; TMP&#34;。&#34; TBDPTYPE&#34;(+)AND&#34; D&#34;。& #34; ABRNCHCOD&#34; =&#34; TMP&#34;&#34; ABRNCHCOD&#34;(+)) 25 11 - 过滤器(&#34; D&#34;。&#34; TDOPNDAT&#34;&lt; = TO_DATE(&#39; 20130601&#39;,&#39; yyyy / mm / dd&#39;)) 26个
27注意 28 ------ 29 - 用于此语句的动态采样(级别= 4) 30 - 由于提示

,并行度为10

我使用/ + leading(d,tmp) / hint执行上述查询。计划如下所示:


计划哈希值:1033900074


| Id |操作|名称|行|字节|成本(%CPU)|时间| TQ | IN-OUT | PQ Distrib |

| 0 |选择声明| | 12M | 1994M | 4255(3)| 00:01:17 | | | | | 1 | PX COORDINATOR | | | | | | | | | | 2 | PX SEND QC(RANDOM)| :TQ10002 | 12M | 1994M | 4255(3)| 00:01:17 | Q1,02 | P-> S | QC(兰德)| | * 3 | HASH JOIN OUTER BUFFERED | | 12M | 1994M | 4255(3)| 00:01:17 | Q1,02 | PCWP | | | 4 | PX RECEIVE | | 12M | 1774M | 4059(2)| 00:01:14 | Q1,02 | PCWP | | | 5 | PX SEND HASH | :TQ10000 | 12M | 1774M | 4059(2)| 00:01:14 | Q1,00 | P-> P |哈希| | 6 | PX BLOCK ITERATOR | | 12M | 1774M | 4059(2)| 00:01:14 | Q1,00 | PCWC | | | * 7 |表访问完全| TDPST | 12M | 1774M | 4059(2)| 00:01:14 | Q1,00 | PCWP | | | 8 | PX RECEIVE | | 3730K | 67M | 178(3)| 00:00:04 | Q1,02 | PCWP | | | 9 | PX SEND HASH | :TQ10001 | 3730K | 67M | 178(3)| 00:00:04 | Q1,01 | P-> P |哈希| | 10 | PX BLOCK ITERATOR | | 3730K | 67M | 178(3)| 00:00:04 | Q1,01 | PCWC | |

| 11 |表访问完全| TMPFHIST | 3730K | 67M | 178(3)| 00:00:04 | Q1,01 | PCWP | |

谓词信息(由操作ID标识):

3 - 访问(&#34; D&#34;。&#34; TDSERIAL&#34; =&#34; TMP&#34;。&#34; TDSERIAL&#34;(+)AND&#34; D&#34;。&#34; CFCIFNO&#34; =&#34; TMP&#34;。&#34; CFCIFNO&#34;(+)AND               &#34; D&#34;。&#34; TBDPTYPE&#34; =&#34; TMP&#34;。&#34; TBDPTYPE&#34;(+)AND&#34; D&#34;。&# 34; ABRNCHCOD&#34; =&#34; TMP&#34;&#34; ABRNCHCOD&#34;(+))    7 - 过滤器(&#34; D&#34;。&#34; TDOPNDAT&#34;&lt; = TO_DATE(&#39; 20130601&#39;,&#39; yyyy / mm / dd&#39;))< / p>

注意

  • 用于此声明的动态采样(级别= 4)
  • 由于提示
  • ,并行度为10

我在d.TDOPNDAT上创建了一个索引,在(tmp.ABRNCHCOD,tmp.TBDPTYPE,tmp.CFCIFNO,tmp.TDSERIAL)上创建了一个索引

。除此之外,Optimizer没有使用任何索引,我强制优化器使用创建的索引,但查询成本增加指数!! 完成所有提到的作品后,查询时间仍然很长!

任何人都有任何建议减少查询时间? 感谢

2 个答案:

答案 0 :(得分:1)

创建中间表不是必需的,因为在给定正确信息的情况下,查询优化器应该能够在一步中以最快的方式做出正确的决定,而无需您完成中间步骤。与索引类似,通常查询优化器将决定是否使用它们 - 只要它具有正确的输入(以统计/约束等形式)。

索引并不总是很好 - 它们在需要找到表中的一小部分数据时非常强大,但是在您阅读整个表格的情况下,它们对您没有多大帮助。

作为一个起点,请询问Oracle使用执行长时间运行查询的计划。这可以通过以下方式完成:

explain plan for 
select .... from  tdpst left outer join fhist 
left outer join dp2act
left outer join dp2cust;

然后,

select * from table(dbms_xplan.display);

注意 - 我在这台笔记本电脑上没有数据库(这是周末),所以上面的命令可能会有一些拼写错误,如果它们没有按预期工作,请查看文档。

查看结果并考虑:     如何加入表 - 是使用散列,合并连接还是嵌套循环?     是以正确的顺序加入表格。

我的猜测是,它会对连接顺序或连接类型做出错误的决定。根据这个假设,接下来我要检查的是基数估计。使用/ * + GATHER_PLAN_STATISTICS * / hint再次运行查询(您需要使用此提示实际运行它 - 不仅仅是解释计划)并使用以下方法检查估计行数和实际行数之间的差异:

SELECT * FROM table(DBMS_XPLAN.DISPLAY_CURSOR(FORMAT =&gt;'ALLSTATS LAST'));

检查估计的行与实际行之间的巨大差异。一个很大的差异意味着统计数据中的问题导致优化器误入歧途。从这一点你可以考虑。

  • 收集表格上的附加统计信息,例如,如果其中一个表格中有一个偏斜的列(请参阅DBMS_STATS)
  • 如果您要加入两个或更多相关列,则收集扩展统计信息

然后重复,看看你是否获得了性能提升

祝你好运..

答案 1 :(得分:0)

首先,通常是让引擎处理索引选择的最佳做法。如果没有使用索引,通常是因为连接的条件不允许正确使用索引。这就是你的执行成本增加的原因。

如果在SSD驱动器上具有最小IO和临时数据库,则临时表是一个不错的选择。环境是这里的一个因素。如果您的数据选择很大,请考虑分页。

否则我会推荐一个索引视图。您的列将使用您的连接指定,并允许预先计算索引以获得最佳结果。我认为Oracle称他们为物化视图。如果您索引每个表中的字段,它还应强制计算连接。

如果我的回答有误,请随时纠正我。我的大多数经验来自MSSQL。我的Oracle经验有点受限