2011-03-18 33 views
2

如果oracle中的查询第一次执行11分钟,并且下一次同一查询25秒,并且缓冲区被刷新,那么可能的原因是什么?这可能是查询写得不好吗?神秘的oracle查询

set timing on; 
set echo on 
set lines 999; 

insert into elegrouptmp select idcll,idgrpl,0 from elegroup where idgrpl = 109999990; 
insert into SLIMONTMP (idpartes, indi, grecptseqs, devs, idcll, idclrelpayl) 
    select rel.idpartes, rel.indi, rel.idgres,rel.iddevs,vpers.idcll,nvl(cdsptc.idcll,vpers.idcll) 
from 
    relbqe rel, 
    elegrouptmp ele, 
    vrdlpers vpers 
    left join cdsptc cdsptc on 
      (cdsptc.idclptcl = vpers.idcll and 
      cdsptc.cdptcs  = 'NOS') 
where 
    rel.idtits = '10BCPGE ' and 
    vpers.idbqes = rel.idpartes and 
    vpers.cdqltptfc = 'N' and 
    vpers.idcll = ele.idelegrpl and 
    ele.idgrpl = 109999990; 

alter system flush shared_pool; 
alter system flush buffer_cache; 
alter system flush global context; 

select /* original */ mvtcta_part_SLIMONtmp.idpartes,mvtcta_part_SLIMONtmp.indi,mvtcta_part_SLIMONtmp.grecptseqs,mvtcta_part_SLIMONtmp.devs, 
mvtcta_part_SLIMONtmp.idcll,mvtcta_part_SLIMONtmp.idclrelpayl,mvtcta_part_vrdlpers1.idcll,mvtcta_part_vrdlpers1.shnas,mvtcta_part_vrdlpers1.cdqltptfc, 
mvtcta_part_vrdlpers1.idbqes,mvtcta_part_compte1.idcll,mvtcta_part_compte1.grecpts,mvtcta_part_compte1.seqc,mvtcta_part_compte1.devs,mvtcta_part_compte1.sldminud, 
mvtcta.idcll,mvtcta.grecptseqs,mvtcta.devs,mvtcta.termel,mvtcta.dtcptl,mvtcta.nusesi,mvtcta.fiches,mvtcta.indl,mvtcta.nuecrs,mvtcta.dtexel,mvtcta.dtvall, 
mvtcta.dtpayl,mvtcta.ioi,mvtcta.mtd,mvtcta.cdlibs,mvtcta.libcps,mvtcta.sldinitd,mvtcta.flagtypei,mvtcta.flagetati,mvtcta.flagwarnl,mvtcta.flagdonei,mvtcta.oriindl, 
mvtcta.idportfl,mvtcta.extnuecrs 
from SLIMONtmp mvtcta_part_SLIMONtmp 
left join vrdlpers mvtcta_part_vrdlpers1 on 
(
    mvtcta_part_vrdlpers1.idbqes = mvtcta_part_SLIMONtmp.idpartes 
    and mvtcta_part_vrdlpers1.cdqltptfc = 'N' 
    and mvtcta_part_vrdlpers1.idcll = mvtcta_part_SLIMONtmp.idcll 
) 
left join compte mvtcta_part_compte1 on 
(
    mvtcta_part_compte1.idcll = mvtcta_part_vrdlpers1.idcll 
    and mvtcta_part_compte1.grecpts = substr (mvtcta_part_SLIMONtmp.grecptseqs, 1, 2) 
    and mvtcta_part_compte1.seqc = substr (mvtcta_part_SLIMONtmp.grecptseqs, -1 ) 
    and mvtcta_part_compte1.devs = mvtcta_part_SLIMONtmp.devs 
    and (mvtcta_part_compte1.devs = ' ' or ' ' = ' ') 
    and mvtcta_part_compte1.cdpartc not in ('L' , 'R') 
) 
left join mvtcta mvtcta on 
(
    mvtcta.idcll = mvtcta_part_SLIMONtmp.idclrelpayl 
    and mvtcta.devs = mvtcta_part_SLIMONtmp.devs 
    and mvtcta.grecptseqs = mvtcta_part_SLIMONtmp.grecptseqs 
    and mvtcta.flagdonei <> 0 
    and mvtcta.devs = mvtcta_part_compte1.devs 
    and mvtcta.dtvall > 20101206 
) 
where 1=1 
order by mvtcta_part_compte1.devs, 
mvtcta_part_SLIMONtmp.idpartes, 
mvtcta_part_SLIMONtmp.idclrelpayl, 
mvtcta_part_SLIMONtmp.grecptseqs, 
mvtcta.dtvall; 
+1

请发布查询和解释计划 – Mat 2011-03-18 09:11:21

+0

并添加确切的Oracle rdbms版本号。为了更容易:在sql_trace运行的同时执行查询。在第一次运行后执行提交并研究跟踪文件。行源操作应该给出一个线索。 – 2011-03-18 10:03:47

回答

4

“如果在Oracle一个查询需要它执行11分钟第一 时间, 接下来的时间,同样的查询25 秒,与缓冲是 冲洗,什么是可能的原因?”

的事情是,冲洗DB缓冲区,像这样...

alter system flush shared_pool 
/

...抹了Oracle数据存储,但也有其他地方的数据被缓存。例如,您的操作系统可能会缓存其文件读取。

EXPLAIN PLAN是数据库认为它将执行查询的一般指南,但它只是一个预测。它可以被糟糕的统计数据或环境条件抛出。它不善于解释为什么查询的特定实例花费尽可能多的时间。

因此,如果您真的想了解当数据库执行特定查询时发生了什么,您需要调低和肮脏,并学习如何使用等待接口。这是一个非常强大的跟踪机制,它允许我们查看单个查询执行过程中发生的各个事件。 Oracle的每个版本都扩展了等待接口的实用性和丰富性,但从Oracle 9i(如果不是更早)开始适当的调整至关重要。

了解更多阅读Roger Schrag's very good overview

在你的情况下,你会想多次运行轨迹。为了便于比较结果,您应该为每次执行使用单独的会话,每次都设置10046事件。

+0

刷新共享池不会影响缓冲区缓存AT ALL。共享池是存储诸如打开游标和分析查询之类的东西的地方。保存实际数据缓冲区的缓冲区缓存完全不同。要刷新数据缓冲区,你需要'ALTER SYSTEM FLUSH BUFFER_CACHE'。除此之外,关于操作系统缓存的观点是有效的。 – 2011-03-18 13:03:08

+0

+1,OS文件系统缓存是重要的一点。 – DCookie 2011-03-18 14:26:47

0

当你跑这些东西时,盒子上还发生了什么?您可以根据其他进程咀嚼资源获得不同的计时。另外,通过大量的连接,性能将取决于内存使用情况(hash_area_size,sort_area_size等)和可用性,因此也许您正在分页(也检查临时空间大小/使用情况)。简而言之,请尝试sql_trace和tkprof以更深入地分析

0

有时在提交之前将块写入文件系统(脏块)。稍后阅读该块时,Oracle会认为它未提交。它检查未完成的交易,并且如果交易不存在,它就知道这个更改已经完成。因此它将块写回干净的块。它被称为延迟块清除。

这是第一次读取块的速度可能低于后续重新读取的一个可能原因。

0

可能是第二次知道执行计划。也许优化器出于某种原因很难找到执行计划。 尝试设置

alter session set optimizer_max_permutations=100; 

,并重新运行查询。看看这是否有所作为。

0
could it be that the query is written in a bad way? 

“坏”是一个比较情绪化的表达 - 但大致来说,是的,如果查询显著更快执行它运行第二次,它通常意味着有一些方法可以优化查询。

事实上,优化查询是 - 正如APC所说 - 而不是“沮丧和肮脏”的问题。明显的候选人可能是子字符串 - 如果表格很大,并且子字符串没有找到索引,我想可能会花费一些时间,我想可以将所有这些substrin操作的结果缓存在某处。

0

这是Tom Kyte's take on flushing Oracle buffers as a testing practice。只要说他不是粉丝就够了。他赞成尝试用您的测试数据(“真实生活”)模拟您的生产负载,并抛出第一次和最后一次运行的方法。 @ APC关于操作系统缓存的观点是汤姆的观点 - 摆脱那种反弹服务器而不仅仅是数据库的(非平凡!)效果。