クラシックケース:DBLINKを使用して、Oracle SQL文を最適化する方法

https://blog.csdn.net/Enmotech/article/details/78788083からの振替

著者は紹介します

趙Quanwen

彼は、Oracle DBAレジデンス運用・保守作業を行うために中央ホールオーディオビジュアル教育では、太地コンピュータ株式会社、株式会社を働きました。Oracleは、実務経験の三年間については、現在、SQLスクリプトを書いて、トラブルシューティングやパフォーマンスの最適化、およびOracleの技術を共有して喜んでされているOracleデータベースに特化しています。

SQL文の一般DBLINKでは、結果セットを表示するインラインリモート・テーブルは、データネットワーク伝送の目的を介して還元を達成するため、データを最小化するために戻った呼び出しではなく、データ伝送のためのネットワークリソースを大量に消費しますイベントを待ちます。Oracleの待機イベントでは、このようなある:メッセージDBLINKからSQL * Netの

それはちょうどので、私たちの本番Oracleデータベースは、まさにそのようないくつかの類似したSQLに遭遇したいくつかの時間前に起こりました。だから、今日、あなたと共有し、最適化のアイデアの最初の使用は、Oracleに対するSQL文の解析をDBLINK。

問題を発見

まず、EMCCモニタから、私たちは長い時間が完了していないため、SQL文が実行されました。

 

640?wx_fmt = PNG&wxfrom = 5&wx_lazy = 1

 

問題分析(A)

次のように完全なSQL文の実行値SQL_IDクロールは、次のとおりです。

 

0?wx_fmt = PNG

 

「1.」バインド変数に上記のSQL文を探します

五$ sql_bind_capture(またはdba_hist_sqlbind)のビューの特定の値によって表示します。

0?wx_fmt = PNG

 

それとも、SQLT(フルネームSQLTXPLAIN、SQLTのダウンロード、インストールおよび使用は、Oracle MOS 215187.1を参照してください)分析SQL_ID生成するために、使用することができます83gn36c1fu9dw「:1、」特定の値(持ってバインド変数があることレポートから見つけるために報告書を、私のデータベース・サーバ上により多くが)、SQLTが展開されている以下に示すように、ここでレポートを生成するプロセスは、バインド変数の値を参照するためのプロセスをスキップします。

 

0?wx_fmt = PNG

0?wx_fmt = PNG

0?wx_fmt = PNG

 

然后,将上面查出的值”ff80808141c605e20141c9691f5a000c”带入原始的SQL语句并在SQL*Plus里执行,运行5分26秒才显示查询结果。可想而知,在当前的高并发情况下,这样的一条SQL语句花很长时间执行不完也就不足为奇了,整个过程如下图所示。

 

0?wx_fmt = PNG

 

分析整个SQL语句的结构

 

其中最外层的SELECT是一个ROWNUM操作,也就是取内层结果集并返回前5行;

再往里的一层完全可以去掉,(这个我经过测试是可行的);

再往里看的一层就是内联视图r (查询远程表sd_res_id_case返回的结果集)与本地表t进行左联接;

最终返回整个查询结果。

大家仔细看一下那个内联视图r,你会发现里面还有一个子查询(就是and rowid in下面的那层)。

生成带统计信息的执行计划,如下图所示:

 

0?wx_fmt = PNG

0?wx_fmt = PNG

 

看第3步的NESTED LOOPS,Starts*E-Rows=1*2=2,而A-Rows=926K,我们说Starts*E-Rows的值和A-Rows的值应该相等或者相差不多,再看第8行的REMOTE,Starts*E-Rows=926K*3,A-Rows=5,这两个值也相差很大。而且这个REMOTE的Starts是926K,这说明要执行这么多次,这个太消耗资源而且还是在远程库的表上。

 

接下来,在执行计划后面的”Remote SQL Information”中可以看出有两个REMOTE操作,也就是说这条SQL语句的内联视图r并不是整体从远程表上查询出结果再返回到本地库,而是先执行第5步,再执行第8步,总共查询了两次远程表。

 

那么试想一下看能不能让远程表只查询一次,也就是让内联视图r只执行一次就返回远程表sd_res_id_case的查询结果?

结果当然是可以的,用一个no_merge的Hint放在内联视图r的第一个select 之后,更改之后是下面这样的:

 

0?wx_fmt = PNG

 

竟然发现大约7秒就查询出结果,如下图所示,

 

0?wx_fmt = PNG

 

接着,查看附加统计信息的执行计划。

 

0?wx_fmt = PNG

0?wx_fmt = PNG

 

最主要的是,执行时间大大降低,而且在执行计划里只有一个REMOTE操作,第二步变成了HASH JOIN操作(原先的执行计划是NESTED LOOPS),估计行和返回行都是5。

 

接下来再看第5行的VIEW操作,执行1次,估行行为5754,实际行为66165,这个相差10倍左右,估计还有优化的空间。

 

远程库上查看内联视图r的数据量

 

由于远程表的执行计划在本地库上无法查看,那么我们到远程库上查询一下原SQL语句的内联视图r,看看到底有多少数据。

 

在远程库上做如下操作。

 

0?wx_fmt = PNG

 

竟然返回196372(约196K)行,这个值高的超乎我想象。

 

查看带统计信息的执行计划,如下图所示,

 

0?wx_fmt = PNG

 

第2行的”NESTED LOOPS”操作实际返回行196K,也就是SQL语句中的最外层select count(*)操作;

第7行的”TABLE ACCESS BY USER ROWID”操作也是实际返回行196K(仔细看,Starts的值为196K,也就是执行196K次,这个好恐怖),第7行的操作就是子查询”select min(rowid) from ……”。

这样看来SQL语句的外层select有多少行,里面的子查询就执行多少次,而现在的外层select是196K行,然后呢,196K*196K = ?我都不敢想……

 

总体上看,加一个no_merge的Hint,先是让SQL的执行时间与原先相比降低了好多。

 

于是,我和开发同事进行沟通,我才明白SQL是应用服务器里跑的一个定时任务,每天凌晨4点开始执行,最后他给程序里的SQL增加no_merge的Hint。

 

问题解析(二)

第二天,我用视图v$active_session_history查看凌晨4点到6点的DBLINK等待事件。

 

0?wx_fmt = PNG

0?wx_fmt = PNG

 

从上面的查询,我们可以看出,有两条SQL的DBLINK等待事件总数多的离谱。其实另外一条SQL和我前面分析的那条唯一的区别就是在select最外层又加了一个ROWNUM <= ":2" 的条件,目前我们只分析原先的那条。

 

那么,再查询6点到7点的情况,已经没有DBLINK的等待事件,说明那些相关的SQL执行完毕,如下图所示。

 

0?wx_fmt = PNG

 

另外,我们从AWR的对比报告中也可以看出上面的查询结果(AWR是从视图DBA_HIST_ACTIVE_SESS_HISTORY中读取相关信息)。

 

0?wx_fmt = PNG

0?wx_fmt = PNG

0?wx_fmt = PNG

 

从上面的AWR图中我们还可以看出那两条SQL的执行次数分别为3106和3039。

 

从前面的执行计划分析,我们了解到SQL主要慢在内联视图r的返回行很多,那么继续优化就是要改写内联视图。

 

首先,将内联视图r的外层select查询中增加和内层select查询中同样的where条件,这样就能过滤掉许多行,同时将两层select查询中的school_id字段进行关联,如下图所示。

 

0?wx_fmt = PNG

 

然而只需4毫秒就显示查询结果,带统计信息的执行计划如下图所示,

 

 

0?wx_fmt = PNG

 

接下来,我和开发同事进行了沟通并把我改写后的SQL发给他,他测试运行和原先SQL相比,也认为在运行时间上差了一个数量级。后来,他根据业务的需求改写了原来的SQL,整个改写后的SQL语句如下图所示。

 

0?wx_fmt = PNG

 

查看带统计信息的执行计划,如下图所示。

 

 

0?wx_fmt = PNG

 

通过上面的执行计划,大家可以看出Starts、E-Rows、A-Rows的值都变得很小了,A-Time的值为1~2毫秒。

 

第三天,再次查看相应时间段的DBLINK等待事件总数,发现与原来相比已经降低了很多。

 

0?wx_fmt = PNG

 

再查看SQL_ID为a50rh3659p44q的SQL在相应对间段的执行次数,见下图。

 

 

0?wx_fmt = PNG

 

同样的,从下面折AWR报告中也能看出和上面的查询一样的效果。

 

0?wx_fmt = PNG

0?wx_fmt = PNG

0?wx_fmt = PNG

总结

最后对使用DBLINK的SQL优化过程总结:

(1) 从EMCC监控上抓取有问题的SQL;

(2) 通过给SQL增加gather_plan_statistics的Hint通过实际运行测试;

(3) 生成相应的行源执行计划并分析哪一步操作最消耗时间;

(4) 找出对应的方法(并不一定是改写,这个根据具体情况而定),再次进行测试;

(5) 与开发人员沟通,并重新审核修改SQL代码。(若无需更改代码的优化,那就再好不过了)

 

相关文献参考:

https://community.oracle.com/thread/4083373

https://community.oracle.com/thread/4100882

 

(アルファベット順)に感謝します:

ジョナサン・ルイス、

アンドリュー・セイヤー、

ビリー・Verreynne、

ビード、

マニク、

perfdba、

Paulzip、

ムスタファKALAYCI、

Cookiemonster76、

スヴェンW.、

両生類

Oracleや他の外国の技術的な専門家が、彼らは、Oracle開発者コミュニティ(https://community.oracle.com/welcome)上で、私の質問を投稿するために慎重に指示を出しました。

おすすめ

転載: www.cnblogs.com/zylong-sys/p/12034551.html