神秘的预言机查询
Posted
技术标签:
【中文标题】神秘的预言机查询【英文标题】:mysterious oracle query 【发布时间】:2011-03-18 09:08:41 【问题描述】:如果 oracle 中的查询第一次执行需要 11 分钟,下一次执行相同的查询需要 25 秒,并且缓冲区被刷新,可能的原因是什么?会不会是查询写的不好?
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;
【问题讨论】:
请发布查询和解释计划 并添加准确的 Oracle rdbms 版本号。为了让事情变得更简单:在 sql_trace 运行时执行两次查询。在第一次运行后执行提交并研究跟踪文件。行源操作应该提供线索。 【参考方案1】:"如果 oracle 中的查询采用第一个 执行时间为 11 分钟,并且 下一次,同样的查询 25 秒,缓冲区是 脸红了,可能是什么原因?”
问题是,像这样刷新 DB 缓冲区...
alter system flush shared_pool
/
... 擦除 Oracle 数据存储,但在其他地方缓存数据。例如,您的操作系统可能会缓存其文件读取。
EXPLAIN PLAN 可以很好地作为数据库认为它将如何执行查询的一般指南,但它只是一个预测。它可能会因糟糕的统计数据或环境条件而被淘汰。它不能很好地解释为什么一个特定的查询实例花费了与它一样多的时间。
因此,如果您真的想了解当数据库执行特定查询时会发生什么,您需要了解如何使用等待接口。这是一个非常强大的跟踪机制,它允许我们查看在单个查询执行过程中发生的各个事件。每个版本的 Oracle 都扩展了等待接口的实用性和丰富性,但自 Oracle 9i(如果不是更早版本)以来,它对于正确调优至关重要。
阅读Roger Schrag's very good overview 了解更多信息。
在您的情况下,您需要多次运行跟踪。为了更容易比较结果,您应该为每次执行使用单独的会话,每次设置 10046 事件。
【讨论】:
刷新共享池根本不会影响缓冲区缓存。共享池是存储打开游标和解析查询等内容的地方。保存实际数据缓冲区的缓冲区缓存完全不同。要刷新数据缓冲区,您可以ALTER SYSTEM FLUSH BUFFER_CACHE
。除此之外,关于操作系统缓存的观点是有效的。【参考方案2】:
当您运行这些时,盒子上还发生了什么?您可以根据其他进程咀嚼资源获得不同的时间。此外,对于很多连接,性能将取决于内存使用情况(hash_area_size、sort_area_size 等)和可用性,所以也许你正在分页(也检查临时空间大小/使用情况)。总之,试试sql_trace 和 tkprof 来深入分析
【讨论】:
【参考方案3】:有时一个块在提交之前被写入文件系统(脏块)。稍后读取该块时,Oracle 发现它未提交。它检查打开的事务,如果事务不存在,它就知道更改已提交。因此,它将块作为一个干净的块写回。称为延迟块清除。
这就是第一次读取块可能比随后的重新读取慢的一个可能原因。
【讨论】:
【参考方案4】:可能是第二次知道执行计划。也许优化器出于某种原因很难找到执行计划。 尝试设置
alter session set optimizer_max_permutations=100;
然后重新运行查询。看看这有什么不同。
【讨论】:
【参考方案5】:could it be that the query is written in a bad way?
“糟糕”是一个相当情绪化的表达方式 - 但从广义上讲,是的,如果查询在第二次运行时执行得明显更快,这通常意味着有办法优化查询。
实际上优化查询是 - 正如 APC 所说 - 而是一个“肮脏和肮脏”的问题。您的示例中明显的候选对象可能是子字符串 - 如果表很大,并且子字符串错过了索引,我想这会花费一些时间,而且我想所有这些子字符串操作的结果都缓存在某个地方.
【讨论】:
【参考方案6】:这里是Tom Kyte's take on flushing Oracle buffers as a testing practice。说他不是粉丝就够了。他赞成尝试用您的测试数据(“现实生活”)模拟您的生产负载并放弃第一次和最后一次运行的方法。 @APC 关于操作系统缓存的观点是 Tom 的观点——要摆脱这种(非平凡的!)影响,您需要反弹服务器,而不仅仅是数据库。
【讨论】:
以上是关于神秘的预言机查询的主要内容,如果未能解决你的问题,请参考以下文章