使用dblink产生的”SELECT /*+ FULL(P) +*/ * FROM XXXXX P ” 解析
在MES平台看到一个提问,应用程序总时会自动产生类似”SELECT /*+ FULL(P) +*/ * FROM XXXXX P “这类SQL,确认不是应用代码中调用,看到FULL hint对于SQL调优人员可能会捶开发人员的冲动 ,同样对于SQL审核或SPA、 数据库国产迁移性能分析等需求抓到这类SQL可能就白白浪费感情。这SQL是数据库自动产生的吗?是!它是DBLINK调用的。
SQL ordered by Parse Calls
Parse Calls | Executions | % Total Parses | SQL Id | SQL Module | SQL Text |
---|---|---|---|---|---|
167,876 | 0 | 5.57 | 6w6wns07k4rg9 | oracle@ANBOBDB2 (TNS V1-V3) | SELECT /*+ FULL(P) +*/ * FROM … |
108,237 | 0 | 3.59 | bmzpf6turfg7r | oracle@ANBOB1 (TNS V1-V3) | SELECT /*+ FULL(P) +*/ * FROM … |
90,194 | 0 | 2.99 | dk5ahnmbrxb8t | oracle@ANBOBDB2 (TNS V1-V3) | SELECT /*+ FULL(P) +*/ * FROM … |
66,035 | 0 | 2.19 | 8kd6cncxab3rz | oracle@ANBOB1 (TNS V1-V3) | SELECT /*+ FULL(P) +*/ * FROM … |
65,964 | 0 | 2.19 | f4s3rg0a635pa | oracle@ANBOB1 (TNS V1-V3) | SELECT /*+ FULL(P) +*/ * FROM … |
65,927 | 0 | 2.19 | 35hrzd1mu3c29 | oracle@ANBOB1 (TNS V1-V3) | SELECT /*+ FULL(P) +*/ * FROM … |
65,807 | 0 | 2.18 | 45h0g7ja0c0xm | oracle@ANBOBDB2 (TNS V1-V3) | SELECT /*+ FULL(P) +*/ * FROM … |
65,807 | 0 | 2.18 | 5accam6g9673q | oracle@ANBOBDB1 (TNS V1-V3) | SELECT /*+ FULL(P) +*/ * FROM … |
65,807 | 0 | 2.18 | 8g506xujwrbmh | oracle@ANBOBDB2 (TNS V1-V3) | SELECT /*+ FULL(P) +*/ * FROM … |
上面是该环境的AWR,下面测试是否是dblink产生,env oracle 19c
创建dblink
note:这里是虚拟机创建一个到本数据库的回路DBLINK
SQL> @cc pdb1 ALTER SESSION SET container = pdb1; SQL> create database link dl_lo connect to anbob identified by xxxxx using 'cdb1pdb1'; Database link created. SQL> select sysdate from dual@dl_lo; SYSDATE ------------------- 2023-06-09 22:52:10
确认DBLINK远程会话
SQL> select sid,username,machine,program from v$session where username is not null;
SID USERNAME MACHINE PROGRAM
---------- ---------- ---------- ------------------------------------------------
12 SYS oel7db1 oracle@oel7db1 (OFSD)
33 SYS oel7db1 sqlplus@oel7db1 (TNS V1-V3)
34 SYS oel7db1 sqlplus@oel7db1 (TNS V1-V3)
68 ANBOB oel7db1 oracle@oel7db1 (TNS V1-V3) 《《《《《《《《《
note:
如果会话较多,使用我之前BLOG Script: Who’s using a database link?(找出谁在使用dblink)
启用SQL trace
SQL> @usid 68 USERNAME SID AUDSID OSUSER MACHINE PROGRAM SPID OPID CPID SQL_ID HASH_VALUE LASTCALL STATUS SADDR PADDR TADDR LOGON_TIM ----------------------- -------------- ----------- ---------------- ------------------ -------------------- -------------- ------ ------------------------ --------------- ----------- ---------- -------- ------ ---------- ---------------- ---------------- --------- ANBOB '68,51112' 4056002 oracle oel7db1 (TNS V1-V3) 7516 47 7380 2bvcw86f03kx9 2617363369 71 INACTIVE 000000 00781281E0 0000000078D0AA88 000000007524CFF0 09-JUN-23 SQL> oradebug setorapid 47 Oracle pid: 47, Unix process pid: 7516, image: oracle@oel7db1 SQL> oradebug event 10046 trace name context forever,level 12; Statement processed. SQL> oradebug tracefile_name; /u01/app/oracle/diag/rdbms/anbob19c/anbob19c/trace/anbob19c_ora_7516.trc
note:
给DBLINK 远程会话启用sql trace, 跟踪是否它产生的SQL。
查询DBLINK调用
SQL> select count(*) from t1@dl_lo; COUNT(*) ---------- 611120
note:
在dblink的调用端执行查询,这里查询的是远程库的T1表。
分析SQL trace file中的SQL
[oracle@oel7db1 ~]$ awk '/PARSING/,/END OF STMT/' /u01/app/oracle/diag/rdbms/anbob19c/anbob19c/trace/anbob19c_ora_7516.trc |egrep -v '^END|PARSING IN'|cat -n 1 select obj#,type#,ctime,mtime,stime, status, dataobj#, flags, oid$, spare1, spare2, spare3, signature, spare7, spare8, spare9, nvl(dflcollid, 16382), creappid, creverid, modappid, modverid, crepatchid, modpatchid from obj$ where owner#=:1 and name=:2 and namespace=:3 and remoteowner is null and linkname is null and subname is null 2 select t.ts#,t.file#,t.block#,nvl(t.bobj#,0),nvl(t.tab#,0),t.intcols,nvl(t.clucols,0),t.flags,t.pctfree$,t.pctused$,t.initrans,t.maxtrans,t.rowcnt,t.blkcnt,t.empcnt,t.avgspc,t.chncnt,t.avgrln,t.analyzetime,t.samplesize,t.cols,t.property,nvl(t.degree,1),nvl(t.instances,1),t.avgspc_flb,t.flbcnt,t.kernelcols,nvl(t.trigflag, 0),nvl(t.spare1,0),nvl(t.spare2,0),t.spare4,t.spare6,ts.cachedblk,ts.cachehit,ts.logicalread,ts.im_imcu_count,ts.im_block_count,ts.im_sys_incarnation,ts.im_stat_update_time,ts.scanrate,nvl(t.acdrflags, 0),nvl(t.acdrtsobj#, 0),t.acdrdefaulttime, nvl(t.acdrrowtsintcol#, 0) from tab$ t,tab_stats$ ts where t.obj#= :1 and t.obj# = ts.obj# (+) 3 select type#,blocks,extents,minexts,maxexts,extsize,extpct,user#,iniexts,NVL(lists,65535),NVL(groups,65535),cachehint,hwmincr, NVL(spare1,0),NVL(scanhint,0),NVL(bitmapranges,0) from seg$ where ts#=:1 and file#=:2 and block#=:3 4 select audit$ from tab$ where obj# = :1 5 select policy#, action# from aud_object_opt$ where object# = :1 and type = 2 6 select i.obj#,i.ts#,i.file#,i.block#,i.intcols,i.type#,i.flags,i.property,i.pctfree$,i.initrans,i.maxtrans,i.blevel,i.leafcnt,i.distkey,i.lblkkey,i.dblkkey,i.clufac,i.cols,i.analyzetime,i.samplesize,i.dataobj#,nvl(i.degree,1),nvl(i.instances,1),i.rowcnt,mod(i.pctthres$,256),i.indmethod#,i.trunccnt,nvl(c.unicols,0),nvl(c.deferrable#+c.valid#,0),nvl(i.spare1,i.intcols),i.spare4,i.spare2,i.spare6,decode(i.pctthres$,null,null,mod(trunc(i.pctthres$/256),256)),nvl(i.evaledition#,1),nvl(i.unusablebefore#,0),nvl(i.unusablebeginning#,0), ist.cachedblk,ist.cachehit,ist.logicalread from ind$ i, ind_stats$ ist, (select enabled, min(intcols) unicols,min(to_number(bitand(defer,1))) deferrable#,min(to_number(bitand(defer,4))) valid# from cdef$ where obj#=:1 and enabled > 1 group by enabled) c where i.obj#=c.enabled(+) and i.obj# = ist.obj#(+) and i.bo#=:1 order by i.obj# 7 select name,intcol#,segcol#,type#,length,nvl(precision#,0),decode(type#,2,nvl(scale,-127/*MAXSB1MINAL*/),178,scale,179,scale,180,scale,181,scale,182,scale,183,scale,231,scale,0),null$,fixedstorage,nvl(deflength,0),default$,rowid,col#,property, nvl(charsetid,0),nvl(charsetform,0),spare1,spare2,nvl(spare3,0), nvl(evaledition#,1),nvl(unusablebefore#,0),nvl(unusablebeginning#,0), case when (type# in (1,8,9,96,112)) then nvl(collid, 16382) else 0 end case, nvl(collintcol#,0), nvl(acdrrescol#, 0), nvl(spare7, 0), nvl(spare9, 0), nvl(spare10, 0) from col$ where obj#=:1 order by intcol# 8 select pos#,intcol#,col#,spare1,bo#,spare2,spare3 from icol$ where obj#=:1 9 select name,intcol#,segcol#,type#,length,nvl(precision#,0),decode(type#,2,nvl(scale,-127/*MAXSB1MINAL*/),178,scale,179,scale,180,scale,181,scale,182,scale,183,scale,231,scale,0),null$,fixedstorage,nvl(deflength,0),default$,rowid,col#,property, nvl(charsetid,0),nvl(charsetform,0),spare1,spare2,nvl(spare3,0), nvl(evaledition#,1),nvl(unusablebefore#,0),nvl(unusablebeginning#,0), case when (type# in (1,8,9,96,112)) then nvl(collid, 16382) else 0 end case, nvl(collintcol#,0), nvl(acdrrescol#, 0), nvl(spare7, 0), nvl(spare9, 0), nvl(spare10, 0) from col$ where obj#=:1 order by intcol# 10 select col#, grantee#, privilege#,max(mod(nvl(option$,0),2)), max(bitand(nvl(option$,0), 8) /8), max(bitand(nvl(option$,0), 16) /16), max(bitand(nvl(option$,0),64) /64), max(bitand(nvl(option$,0), 128) /128) from objauth$ where obj#=:1 and col# is not null group by privilege#, col#, grantee# order by col#, grantee# 11 select grantee#,privilege#,nvl(col#,0),max(mod(nvl(option$,0),2)),max(bitand(nvl(option$,0), 8) /8), max(bitand(nvl(option$,0), 16) /16), max(bitand(nvl(option$,0),64) /64), max(bitand(nvl(option$,0), 128) /128) from objauth$ where obj#=:1 group by grantee#,privilege#,nvl(col#,0) order by grantee# 12 select col#,intcol#,toid,version#,packed,intcols,intcol#s,flags, synobj#, nvl(typidcol#, 0) from coltype$ where obj#=:1 order by intcol# desc 13 select intcol#, toid, version#, intcols, intcol#s, flags, synobj# from subcoltype$ where obj#=:1 order by intcol# asc 14 select col#,intcol#,ntab# from ntab$ where obj#=:1 order by intcol# asc 15 select l.col#, l.intcol#, l.lobj#, l.ind#, l.ts#, l.file#, l.block#, l.chunk, l.pctversion$, l.flags, l.property, l.retention, l.freepools from lob$ l where l.obj# = :1 order by l.intcol# asc 16 select col#,intcol#,reftyp,stabid,expctoid from refcon$ where obj#=:1 order by intcol# asc 17 select col#,intcol#,charsetid,charsetform from col$ where obj#=:1 order by intcol# asc 18 select intcol#,type,flags,lobcol,objcol,extracol,schemaoid, elemnum from opqtype$ where obj# = :1 order by intcol# asc 19 select o.owner#,o.name,o.namespace,o.remoteowner,o.linkname,o.subname from obj$ o where o.obj#=:1 20 select binaryDefVal, lengthb(binaryDefVal), guard_id from ecol$ where tabobj# = :1 and colnum = :2 21 select parttype, partcnt, partkeycols, flags, defts#, defpctfree, defpctused, definitrans, defmaxtrans, deftiniexts, defextsize, defminexts, defmaxexts, defextpct, deflists, defgroups, deflogging, spare1, mod(spare2, 256) subparttype, mod(trunc(spare2/256), 256) subpartkeycols, mod(trunc(spare2/65536), 65536) defsubpartcnt, mod(trunc(spare2/4294967296), 256) defhscflags, mod(trunc(spare2/1099511627776), 4096) defimcflags, mod(trunc(spare2/4503599627370496), 8) defimcpl, mod(spare3, 256) interval_dty, rowid, defmaxsize, mod(trunc(spare3/256), 256) subptn_interval_dty, mod(trunc(spare3/65536), 256) defccflags, mod(trunc(spare3/16777216), 256) defimcflags2, mod(trunc(spare3/4294967296), 256) defhscflags2 from partobj$ where obj# = :1 22 select con#,obj#,rcon#,enabled,nvl(defer,0),spare2,spare3,refact from cdef$ where robj#=:1 23 select con#,type#,condlength,intcols,robj#,rcon#,match#,refact,nvl(enabled,0),rowid,cols,nvl(defer,0),mtime,nvl(spare1,0),spare2,spare3 from cdef$ where obj#=:1 24 select /*+ rule */ bucket_cnt, row_cnt, cache_cnt, null_cnt, timestamp#, sample_size, minimum, maximum, distcnt, lowval, hival, density, col#, spare1, spare2, avgcln, minimum_enc, maximum_enc from hist_head$ where obj#=:1 and intcol#=:2 25 select /* QOSD */ /*+ index(do) */ dir_cnt from opt_directive_own$ do where dir_own# = :1 26 SELECT /* OPT_DYN_SAMP */ /*+ ALL_ROWS IGNORE_WHERE_CLAUSE RESULT_CACHE(SNAPSHOT=3600) opt_param('parallel_execution_enabled', 'false') NO_PARALLEL(SAMPLESUB) NO_PARALLEL_INDEX(SAMPLESUB) NO_SQL_TUNE */ NVL(SUM(C1),:"SYS_B_0"), NVL(SUM(C2),:"SYS_B_1") FROM (SELECT /*+ NO_PARALLEL("P") FULL("P") NO_PARALLEL_INDEX("P") */ :"SYS_B_2" AS C1, :"SYS_B_3" AS C2 FROM "ANBOB"."T1" SAMPLE BLOCK (:"SYS_B_4" , :"SYS_B_5") SEED (:"SYS_B_6") "P") SAMPLESUB 27 select /* QOSD */ /*+ index(eh)*/ objn, sub_id, fixed_cost, text, col_list, flags, ctime from exp_head$ eh where exp_id = :1 28 SELECT /*+ FULL(P) +*/ * FROM "T1" P 29 SELECT /* OPT_DYN_SAMP */ /*+ ALL_ROWS IGNORE_WHERE_CLAUSE RESULT_CACHE(SNAPSHOT=3600) opt_param('parallel_execution_enabled', 'false') NO_PARALLEL(SAMPLESUB) NO_PARALLEL_INDEX(SAMPLESUB) NO_SQL_TUNE */ NVL(SUM(C1),:"SYS_B_0"), NVL(SUM(C2),:"SYS_B_1") FROM (SELECT /*+ NO_PARALLEL("P") FULL("P") NO_PARALLEL_INDEX("P") */ :"SYS_B_2" AS C1, :"SYS_B_3" AS C2 FROM "ANBOB"."T1" SAMPLE BLOCK (:"SYS_B_4" , :"SYS_B_5") SEED (:"SYS_B_6") "P") SAMPLESUB 30 SELECT /* OPT_DYN_SAMP */ /*+ ALL_ROWS IGNORE_WHERE_CLAUSE RESULT_CACHE(SNAPSHOT=3600) opt_param('parallel_execution_enabled', 'false') NO_PARALLEL(SAMPLESUB) NO_PARALLEL_INDEX(SAMPLESUB) NO_SQL_TUNE */ NVL(SUM(C1),:"SYS_B_0"), NVL(SUM(C2),:"SYS_B_1") FROM (SELECT /*+ NO_PARALLEL("A1") FULL("A1") NO_PARALLEL_INDEX("A1") */ :"SYS_B_2" AS C1, :"SYS_B_3" AS C2 FROM "ANBOB"."T1" SAMPLE BLOCK (:"SYS_B_4" , :"SYS_B_5") SEED (:"SYS_B_6") "A1") SAMPLESUB 31 SELECT COUNT(*) FROM "T1" "A1"
Note:
能看到SQL中确实调用了SELECT /*+ FULL(P) +*/ * FROM “T1” P ,还有一些和表相关的动态采样(未收统计信息原因).
格式化SQL TRACE
[oracle@oel7db1 ~]$ tkprof /u01/app/oracle/diag/rdbms/anbob19c/anbob19c/trace/anbob19c_ora_7516.trc a.out TKPROF: Release 19.0.0.0.0 - Development on Fri Jun 9 22:57:29 2023 Copyright (c) 1982, 2019, Oracle and/or its affiliates. All rights reserved. [oracle@oel7db1 ~]$ vi a.out SQL ID: 1qffndqtbsbhy Plan Hash: 0 SELECT /*+ FULL(P) +*/ * FROM "T1" P call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.01 0.02 1 2 0 0 Execute 0 0.00 0.00 0 0 0 0 Fetch 0 0.00 0.00 0 0 0 0 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 1 0.01 0.02 1 2 0 0 Misses in library cache during parse: 1 Optimizer mode: ALL_ROWS Parsing user id: 106
Note:
sql文本虽然使用的是select 全表扫描,但此SQL仅有parse,并没有真正的execute,也没有fetch任何一条数据。
小结:
SELECT /*+ FULL(P) +*/ * FROM XXXXX P 这种SQL是ORACLE的内部机制在dblink的目标数据库自动触发的解析。注意仅是“解析” 实际不会执行也不会fetch任何数据,所以AWR中也确认只有parse calles,executions全为0,
目的应该远程传递给本地节点进行SQL语义检查, 不是bug.
对不起,这篇文章暂时关闭评论。