Expert One-on-One Oracle阅读笔记(2)
alter tablespace tts_ex2 read
write;
注意到使用的用户,在8.1.6后必须使用SYSDBA帐户才能执行传输,之前则DBA即可。
获得DDL
SHOW=Y和INDEXFILE=文件名两种选项均可显示DDL,但前者的显示断行不合理、语句均加上了双引号,因此倾向使用INDEXFILE选项;但IMP在INDEXFILE选项中不显示触发器和视图的DDL。
1.获取程序包、函数和存储过程代码:@getcode
procedure_name
REM getcode.sql
SET feedback OFF
SET heading OFF
SET termout OFF
SET linesize 1000
SET trimspool ON
SET verify OFF
SPOOL &1.sql
PROMPT SET DEFINE
OFF
SELECT
DECODE(type||'-'||TO_CHAR(line,'fm99999'),'PACKAGE
BODY-1','/'||CHR(10),NULL)||DECODE(line,1,'create or replace','')||text
text
FROM user_source
whre
name=UPPER('&&1')
ORDER BY
TYPE,line;
PROMPT /
PROMPT SET DEFINE
ON
SPOOL OFF
SET feedback ON
SET heading ON
SET termout ON
SET linesize 100
2.获得视图DDL:@getaview
view_name
REM getaview.sql
SET feedback OFF
SET heading OFF
SET termout OFF
SET linesize 1000
SET trimspool ON
SET verify OFF
SET LONG 99999999
SET embedded ON
SPOOL &1.sql
PROMPT CREATE OR REPLACE VIEW &1(SELECT
DECODE(column_id,1,'',',')||column_name column_name FROM user_tab_columns WHERE
TABLE table_name=UPPER('&1') ORDER BY
column_id;
PROMPT AS SELECT text FROM user_views WHERE
view_name=UPPER('&1')
PROMPT /
SPOOL OFF
SET feedback ON
SET heading ON
SET termout ON
SET linesize 100
3. 触发器DDL:@gettrig
trigger_name
REM
gettrig.sql
SET feedback OFF
SET heading OFF
SET termout OFF
SET trimspool ON
SET verify OFF
SET LONG 99999999
SPOOL &1.sql
SELECT 'CREATE OR REPLACE
TRIGGER('''||trigger_name||'''||chr(10)||decode(substr(trigger_type,1,1),'A','AFTER','B','BEFORE','T',INSTEAD
OF')||CHR(10)||triggering_event||CHR(10)||'ON'''||table_owner||'''.'''||table_name||''''||CHR(10)||DECODE(INSTR(trigger_type,'EACH
ROW'),0,NULL,'FOR EACH ROW')||CHR(10),trigger_body FROM user_triggers WHERE
trigger_name=UPPER('&1')
/
PROMPT /
SPOOL OFF
SET feedback ON
SET heading ON
SET termout ON
导入到不同结构
1. 增加了列
不需要额外工作,通常将增加的列设为NULL或其他指定的默认值。
2. 减少了列
将修改后的表改名,并用原表名建立视图,对视图建立INSTEAD OF
INSERT…的触发器。
3. 改变了列的数据类型
同上2的方法。
直接路径导出
即DIRECT=Y。此模式绕过了SQL评估缓冲区,QUERY选项失效,但可以节省10%的处理。
8.2 警告和错误
克隆
使用EXP/IMP克隆用户时要注意,完整性约束(特别是显式声明参照同一方案下表的外键,如REFERENCES
FROMUSER.TABLE)将自动根据FROMUSER和TOUSER更改所有者,而参照其他方案下表的外键、显式声明基于同一方案下表的视图(如… AS SELECT
* FROM FROMUSER.TABLE)和触发器将不会改变所有者,这样如果IMP入的库中有与FROMUSER同名的用户或TOUSER权限不足,将产生错误。因此在运行前,应检查所有的DDL、触发器和过程等:
imp userid=… from user=tkyte touser=a
indexfile=….sql
imp userid=… from user=tkyte touser=a
show=y
跨版本使用IMP/EXP
规则:IMP采用导入数据库的版本;EXP采用两个数据库中较低的版本。
索引的丢失
EXP/IMP后,系统命名的“冗余”索引将会丢失,原因有二:
1. 系统设定的索引名可能与导入数据库中已有的系统分配的索引名重复;
2. 对象的创建本身可能已经创建了索引,即再导入隐式索引可能重复。
第2点即说明所谓“冗余”:在创建表时隐式创建了主键,随后创建一个第一字段就是主键列的索引,那么该表上实际有两个索引;但变换顺序,先创建后面的索引,再显式创建主键,结果是系统用该索引来加强主键,并不创建新索引。后者的情况就如同EXP/IMP的选择,是正确的。
重复导入导致增加冗余约束
对于含有系统命名约束(如check等)的表,导出后如果多次执行导入,虽然会提示约束名已被占用而不会重复导入约束,但仍会每次添加一些重复约束,从而导致性能的下降。因此综合之前几点,还是应该使用显式命名的约束。
NLS问题
在导出和导入时看到possible
charset conversion的提示就应当注意字符集问题,应将系统NLS_LANG设置与数据库字符集一致。
表跨越多个表空间
对于单个表空间的表,导入时未找到表空间或配额不足,IMP将重写SQL,使用导入库的缺省表空间来导入。而对跨越多个表空间的表(如分区表等),IMP不会如此。唯一方法是事先建立类似表空间结构的表再导入。
第 9
章 数据装载
9.1 SQL
Loader简介
9.2 如何装载
装载定界数据
TERMINATED
BY WHITESPACE通过查找下一个非空格字符(即不是制表符、空格或换行)位置来定位。
装载固定格式数据
POSITION(*:..)中*指示控制文件在最后字段停止位置重新开始,并可用+、-进行相对位置移动。另外POSITION子句可以使用重叠位置,并在记录中往返。
装载日期
使用序列和其他函数装载数据
更新现有的行和插入新行
装载报表类型的输入数据
装载文件到一个长RAW或LONG字段中
装载含换行符的数据
1. 使用其它字符代替换行符,导入时替换
如果控制了数据文件的产生,可用例如“\n”类的字符来替代换行符,在导入时用
字段名
“replace(:字段名,’\n’,chr(10))”(Win平台)和字段名
“replace(:字段名,’\\n’,chr(10))”(UNIX平台)
来替代。
2. 使用FIX属性
使用形如INFILE
….DAT “fix nnn”的选项,则指定数据文件每行长度nnn。必须注意的是,在UNIX平台下,换行仅为”\n”,而在Win平台下为”\r\n”,这样用这种方法最好确保生成数据文件的平台和导入的平台一致,否则由于每行长度不同容易出错。
3. 使用VAR属性
同前,使用INFILE
….DAT “var n”,即数据文件每行的前n个字符说明该行长度。
4. 使用STR属性
为数据文件设立新的分隔符,使用INFILE
….DAT “str X’ooo’”,即ooo作为分隔符,而不是换行符。其中ooo是如下获得的16进制数:
SELECT UTL_RAW.CAST_TO_RAW(…) FROM
DUAL;
5. 内嵌的换行符换行
卸载数据
CREATE OR REPLACE PACKAGE
UNLOADER
AS
FUNCTION
RUN( P_QUERY IN
VARCHAR2,
P_TNAME IN
VARCHAR2,
P_MODE IN VARCHAR2 DEFAULT
'REPLACE',
P_DIR IN
VARCHAR2,
P_FILENAME IN
VARCHAR2,
P_SEPARATOR IN VARCHAR2 DEFAULT ',',
P_ENCLOSURE IN VARCHAR2 DEFAULT '"',
P_TERMINATOR IN VARCHAR2 DEFAULT '|'
)
RETURN
NUMBER;
END;
/
CREATE OR REPLACE PACKAGE BODY
UNLOADER
AS
G_THECURSOR
INTEGER DEFAULT DBMS_SQL.OPEN_CURSOR;
G_DESCTBL
DBMS_SQL.DESC_TAB;
G_NL
VARCHAR2(2) DEFAULT CHR(10);
FUNCTION TO_HEX( P_STR IN VARCHAR2 ) RETURN
VARCHAR2
IS
BEGIN
RETURN
TO_CHAR( ASCII(P_STR), 'FM0X' );
END;
PROCEDURE
DUMP_CTL( P_DIR IN
VARCHAR2,
P_FILENAME IN VARCHAR2,
P_TNAME IN VARCHAR2,
P_MODE IN VARCHAR2,
P_SEPARATOR IN VARCHAR2,
P_ENCLOSURE IN
VARCHAR2,
P_TERMINATOR IN VARCHAR2 )
IS
L_OUTPUT
UTL_FILE.FILE_TYPE;
L_SEP
VARCHAR2(5);
L_STR
VARCHAR2(5);
L_PATH
VARCHAR2(5);
BEGIN
IF ( P_DIR
LIKE '%\%' )
THEN
--
WINDOWS PLATFORMS --
L_STR
:= CHR(13) || CHR(10);
IF (
P_DIR NOT LIKE '%\' AND P_FILENAME NOT LIKE '\%'
)
THEN
L_PATH := '\';
END
IF;
ELSE
L_STR
:= CHR(10);
IF (
P_DIR NOT LIKE '%/' AND P_FILENAME NOT LIKE '/%'
)
THEN
L_PATH := '/';
END
IF;
END
IF;
L_OUTPUT
:= UTL_FILE.FOPEN( P_DIR, P_FILENAME || '.CTL', 'W'
);
UTL_FILE.PUT_LINE( L_OUTPUT, 'LOAD DATA'
);
UTL_FILE.PUT_LINE( L_OUTPUT, 'INFILE ''' || P_DIR || L_PATH ||
P_FILENAME || '.DAT'' "STR X''' ||
UTL_RAW.CAST_TO_RAW( P_TERMINATOR ||
L_STR ) || '''"'
);
UTL_FILE.PUT_LINE( L_OUTPUT, 'INTO TABLE ' || P_TNAME
);
UTL_FILE.PUT_LINE( L_OUTPUT, P_MODE
);
UTL_FILE.PUT_LINE( L_OUTPUT, 'FIELDS TERMINATED BY X''' ||
TO_HEX(P_SEPARATOR) ||
''' ENCLOSED
BY X''' ||
TO_HEX(P_ENCLOSURE) || ''' ' );
UTL_FILE.PUT_LINE( L_OUTPUT, '(' );
FOR I IN 1
.. G_DESCTBL.COUNT
LOOP
IF (
G_DESCTBL(I).COL_TYPE = 12 )
THEN
UTL_FILE.PUT( L_OUTPUT, L_SEP || G_DESCTBL(I).COL_NAME ||
' DATE
''DDMMYYYYHH24MISS'' ');
ELSE
UTL_FILE.PUT( L_OUTPUT, L_SEP || G_DESCTBL(I).COL_NAME ||
' CHAR(' ||
TO_CHAR(G_DESCTBL(I).COL_MAX_LEN*2) ||' )'
);
END
IF;
L_SEP
:= ','||G_NL ;
END
LOOP;
UTL_FILE.PUT_LINE( L_OUTPUT, G_NL || ')'
);
UTL_FILE.FCLOSE( L_OUTPUT );
END;
FUNCTION QUOTE(P_STR IN VARCHAR2, P_ENCLOSURE IN
VARCHAR2)
RETURN VARCHAR2
IS
BEGIN
RETURN
P_ENCLOSURE ||
REPLACE( P_STR, P_ENCLOSURE, P_ENCLOSURE||P_ENCLOSURE ) ||
P_ENCLOSURE;
END;
FUNCTION RUN( P_QUERY IN
VARCHAR2,
P_TNAME IN
VARCHAR2,
P_MODE IN VARCHAR2 DEFAULT
'REPLACE',
P_DIR IN
VARCHAR2,
P_FILENAME IN
VARCHAR2,
P_SEPARATOR IN VARCHAR2 DEFAULT ',',
P_ENCLOSURE IN VARCHAR2 DEFAULT '"',
P_TERMINATOR IN VARCHAR2 DEFAULT '|' ) RETURN
NUMBER
IS
L_OUTPUT
UTL_FILE.FILE_TYPE;
L_COLUMNVALUE
VARCHAR2(4000);
L_COLCNT NUMBER DEFAULT
0;
L_SEPARATOR VARCHAR2(10)
DEFAULT '';
L_CNT NUMBER DEFAULT
0;
L_LINE
LONG;
L_DATEFMT VARCHAR2(255);
L_DESCTBL
DBMS_SQL.DESC_TAB;
BEGIN
SELECT
VALUE
INTO
L_DATEFMT
FROM
NLS_SESSION_PARAMETERS
WHERE
PARAMETER = 'NLS_DATE_FORMAT';
/*
SET THE
DATE FORMAT TO A BIG NUMERIC STRING. AVOIDS
ALL NLS
ISSUES AND SAVES BOTH THE TIME AND DATE.
*/
EXECUTE
IMMEDIATE
'ALTER
SESSION SET NLS_DATE_FORMAT=''DDMMYYYYHH24MISS''
';
/*
SET UP
AN EXCEPTION BLOCK SO THAT IN THE EVENT OF
ANY
ERROR,
WE CAN AT LEAST RESET THE DATE FORMAT BACK.
*/
BEGIN
/*
PARSE AND DESCRIBE THE QUERY. WE RESET THE
DESCTBL TO AN EMPTY TABLE SO .COUNT ON IT
WILL BE RELIABLE.
*/
DBMS_SQL.PARSE( G_THECURSOR, P_QUERY, DBMS_SQL.NATIVE
);
G_DESCTBL := L_DESCTBL;
DBMS_SQL.DESCRIBE_COLUMNS( G_THECURSOR, L_COLCNT, G_DESCTBL
);
/*
CREATE A CONTROL FILE TO RELOAD THIS
DATA
INTO THE DESIRED TABLE.
*/
DUMP_CTL( P_DIR, P_FILENAME, P_TNAME, P_MODE, P_SEPARATOR,
P_ENCLOSURE,
P_TERMINATOR );
/*
BIND EVERY SINGLE COLUMN TO A VARCHAR2(4000). WE DON'T CARE
IF
WE ARE FETCHING A NUMBER OR A DATE OR
WHATEVER.
EVERYTHING CAN BE A STRING.
*/
FOR I
IN 1 .. L_COLCNT LOOP
DBMS_SQL.DEFINE_COLUMN( G_THECURSOR, I, L_COLUMNVALUE, 4000
);
END
LOOP;
/*
RUN
THE QUERY - IGNORE THE OUTPUT OF EXECUTE. IT IS ONLY
VALID WHEN THE DML IS AN INSERT/UPDATE OR DELETE.
*/
L_CNT
:= DBMS_SQL.EXECUTE(G_THECURSOR);
/*
OPEN THE FILE TO WRITE OUTPUT TO AND THEN WRITE
THE
DELIMITED DATA TO IT.
*/
L_OUTPUT := UTL_FILE.FOPEN( P_DIR, P_FILENAME || '.DAT', 'W',
32760 );
LOOP
EXIT WHEN ( DBMS_SQL.FETCH_ROWS(G_THECURSOR) <= 0
);
L_SEPARATOR := '';
L_LINE := NULL;
FOR I IN 1 .. L_COLCNT LOOP
DBMS_SQL.COLUMN_VALUE( G_THECURSOR, I,
L_COLUMNVALUE );
L_LINE := L_LINE || L_SEPARATOR ||
QUOTE(
L_COLUMNVALUE, P_ENCLOSURE );
L_SEPARATOR := P_SEPARATOR;
END LOOP;
L_LINE := L_LINE || P_TERMINATOR;
UTL_FILE.PUT_LINE( L_OUTPUT, L_LINE
);
L_CNT := L_CNT+1;
END
LOOP;
UTL_FILE.FCLOSE( L_OUTPUT );
/*
NOW
RESET THE DATE FORMAT AND RETURN THE NUMBER OF
ROWS
WRITTEN TO THE OUTPUT FILE.
*/
EXECUTE IMMEDIATE
'ALTER SESSION SET NLS_DATE_FORMAT=''' || L_DATEFMT ||
'''';
RETURN
L_CNT;
--
EXCEPTION
/*
IN
THE EVENT OF ANY ERROR, RESET THE DATA FORMAT
AND
RE-RAISE THE
ERROR.
*/
--
WHEN OTHERS THEN
--
EXECUTE IMMEDIATE
--
'ALTER SESSION SET NLS_DATE_FORMAT=''' || L_DATEFMT ||
'''';
--
RAISE;
END;
END RUN;
END UNLOADER;
/
装载LOB
1. 利用PL/SQL
CREATE OR
REPLACE DIRECTORY 目录名
AS ‘路径’;
DECLARE
L_CLOB
CLOB;
L_BFILE
BFILE;
BEGIN
INSERT
INTO DEMO VALUES ( 1, EMPTY_CLOB() )
RETURNING
THECLOB INTO L_CLOB;
--若路径名定义时未用””,则内部转换为全大写
L_BFILE := BFILENAME( '路径名',
'文件名'
);
DBMS_LOB.FILEOPEN( L_BFILE );
DBMS_LOB.LOADFROMFILE( L_CLOB,
L_BFILE,
DBMS_LOB.GETLENGTH(
L_BFILE ) );
DBMS_LOB.FILECLOSE( L_BFILE );
END;
/
2. 使用SQLLDR
i.
装载同一行的LOB数据
这里注意LOB数据中往往含有逗号、换行符等,那么确定分割符时同前,Win平台为”str
X’7C0D0A’”而UNIX平台是”str
X’7C0A’”,其次可以将LOB的那个字段类型最大说明为CHAR(1000000)。
ii.
装载不在同行中的LOB数据
即数据文件中某列包含了需要装载到LOB的文件名。则ctl文件中数据类型说明部分为“字段名
LOBFILE(含文件名的字段名)
TERMINATED BY EOF”。
iii.
装载LOB数据到对象列
用SQLLDR装载VARRAYS/嵌套表
在存储过程中调用SQLLDR
无法调用。只能用PL/SQL、Java、C来实现一个小SQLLDR。
9.3 警告
不能选择要使用的回滚段
使用REPLACE选项,将在导入前产生DELETE命令,可能产生大量回滚,但Oracle不允许选择回滚段。
TRUNCATE的不同作用
假设将要装载相似数量的数据,则可使用TRUNCATE的扩展形式:
TRUNCATE TABLE … REUSE
STORAGE
这样并未释放空间,只是将空间均标志为自由空间。
SQLLDR默认为CHAR(255)
要导入更长的文本,只需显式指定CHAR(N)。
命令行取代控制文件
对于例如INFILE等命令行与控制文件均可指定的参数,命令行具有优先级。
第 10
章 优化策略与工具
10.1 标识问题
10.2 我的方法
10.3 绑定变量与分析(再次)
不使用绑定变量将增加语句分析,除了消耗CPU时间外,还会增加字典高速缓存上的闩锁。
显示会话等待的事件:V$SESSION_EVENT。具体事件名和含义可以参考Oracle
Reference Manual的附录Oracle Wait
Events。
CURSOR_SHARING
CURSOR_SHARING参数缺省为EXACT,若指定为FORCE,则优化器可能将语句中所有的常数转换为绑定变量,虽然减少了语句分析,但是也会带来如下副作用:
优化器可供利用的信息可能减少,从而改变执行路径,例如条件中对于某个特定值索引有较好的选择性,改为绑定变量时优化器并不会发现这一点。
查询输出格式发生变化。虽然返回的数据长度不变,但列的长度可能改变。例如对于SELECT id,
‘tom’ name from emp; name应该为VARCHAR2(3),但是由于’tom’被改为绑定变量,则可能name的显示长度变为32。
查询计划更难评估。由于语句的改变,EXPLAIN
PLAN看到的查询与数据库看到的可能不一致,从而使AUTOTRACE等的输出与实际执行路径不一致。
因此,完善的应用系统不应当依靠CURSOR_SHARING来提高效率,仅能作为权宜之计。
10.4 SQL_TRACE,
TIMED_STATISTICS与TKPROF
TIMED_STATISTICS并不会对系统产生过大负担,因此建议设置为TRUE。
启动跟踪
SQL_TRACE可在系统或会话级激活。激活后跟踪文件将产生至init.ora参数USER_DUMP_DEST(专用服务器)或BACKGROUND_DUMP_DEST(MTS)指定的目录。而文件大小通过MAX_DUMP_FILE_SIZE控制,其设置有如下三种方法:
仅数值:以OS块为单位;
数值+K/M:指定文件绝对大小;
UNLIMITED:无上限。
一般只需要设置50-100M就足够了。
激活SQL_TRACE的几种常用方式如下:
ALTER SESSION SET
SQL_TRACE=TRUE|FALSE;
SYS.DBMS_SYSTEM.SET_SQL_TRACE_IN_SESSION
这里我们需要指定SID和SERIAL#(参考V$SESSION);
ALTER
SESSION SET EVENTS. 可获得更详细的信息。
此外也可通过DBMS_SUPPORT包,相当于EVENTS跟踪的一个界面,但此包需要Oracle人员支持,非标配。
随着WEB服务方式的普及,往往一个数据库会话很短,难以单独跟踪,对此,我们可以根据用户,在数据库级建立触发器:
CREATE OR REPLACE TRIGGER
logon_trigger
AFTER LOGON ON
DATABASE
BEGIN
IF ( USER=
‘TKYTE’ ) THEN
EXECUTE
IMMEDIATE ‘ALTER SESSION SET EVENTS ‘ ’10046 TRACE NAME CONTEXT FOREVER, LEVEL
4’ ‘
’;
END IF;
END;/
使用并解析TKPROF输出
1. 激活SQL_TRACE后,通过如下查询检查SPID:
SELECT a.spid
FROM v$process a, v$session b
WHERE a.addr =
b.paddr
AND b.audsid =
userenv(‘sessionid’);
此SPID就包含在跟踪文件的文件名中。
UNIX系统中,若你不在Oracle的管理组中,则生成的跟踪文件所在目录可能无法访问,此时需要设定init.ora参数_trace_files_public
= true 。
2. TKPROF语法: TKPROF *.trc
*.txt
其他用法可以直接运行TKPROF查看。一般常用选项就是-sort,可以根据某些参数值排序。
3. 对跟踪文件输出的一些解释:
i.
行:
PARSE阶段:包括了软分析(在SHARED_POOL中找到语句)和硬分析;
EXECUTE阶段:对SELECT几乎为空,对UPDATE则几乎是全部工作的体现;
FETCH阶段:对SELECT是几乎所有的工作,对UPDATE则为空。
ii.
列:
COUNT:事件发生的次数;
CPU:消耗的CPU时间(CPU秒);
ELAPSED:总体运行时间;
DISK:磁盘物理I/O;
QUERY:一致读模式访问的块数,也包括了从回滚段读取的块数;
CURRENT:访问的当前信息数据块(而不是一致读模式),例如SELECT时读取数据字典内容,修改时也需要访问数据字典内容以写。
ROWS:所涉及的行数。
4. 需要注意的现象:
i.
高的PARSE
COUNT/EXECUTE COUNT(接近100%),且EXECUTE
COUNT大于1
即执行语句时分析的次数,如果过高,可能是软分析也过多了,对一个会话,应该是分析一次反复执行。
ii.
对几乎所有SQL,EXECUTE
COUNT都是1
可能没有使用绑定变量。在一个真实应用中,应该很少看到不同的SQL,同一个SQL应执行多次。
iii.
CPU和ELAPSED时间相差较大
说明花了很长时间等待一个事件,例如磁盘I/O、锁等。
iv. (FETCH
COUNT)/(ROWS FETCHED)比例高
没有很好的使用批量提取。批量提取数据的方法是和语言/API相关的,例如Pro*
C中需要使用prefetch=NN预编译,Java/JDBC下可以调用SETROWPREFETCH方法,PL/SQL可以在SELECT
INTO中直接使用BULK
COLLECT。而SQL*
PLUS缺省为每次取15行。
v.
极大的DISK
COUNT
较难推断,但若DISK COUNT
= QUERY + CURRENT MODE BLOCK COUNT,则说明几乎所有数据都来自磁盘。此时需要考虑SGA大小和此查询效率。
vi.
极大的QUERY
COUNT或CURRENT
COUNT
SQL工作量很大,需要注意。
5. EXPLAIN
PLAN问题
跟踪文件中显示的是真正执行的路径。TKPROF也支持EXPLAIN=XXX/XXX选项,不建议使用,其输出是转换跟踪文件当时优化器选择的执行路径,并是利用数据库的EXPLAIN工具,与真实路径时不完全一致的。
使用与解析原始跟踪文件
1. EVENTS跟踪
ALTER SESSION SET EVENTS ‘10046 trace name context
forever, level N’;
N=1
同标准SQL_TRACE;
N=4
增加获得绑定变量值;
N=8
增加获得查询级的等待事件;
N=12
增加获得绑定变量值和查询级的等待事件。
2. 原始跟踪文件分段解析
文件头含有时间、数据库版本、OS版本、实例名等。
APPNAME mod=’%s’ mh=%lu act=’%s’
ah=%lu
mod
传入DBMS_APPLICATION_INFO的模块名
mh
模块哈希值
act
传入DBMS_APPLICATION_INFO的动作
ah
动作哈希值
Parsing in Cursor #%d dep=%d uid=%ld oct=%d lid=%ld
tim=%ld hv=%ld ad=’%s’
Cursor #
游标号。也可以用此值获知应用最大打开的游标数。
len
下面SQL语句的长度
dep
SQL语句的递归(recursive)深度
uid
当前方案的用户ID。注意,这并不一定和后面的lid一致,因为可以用
alter
session set current_schema来修改分析时的方案
oct
Oracle命令类型(Oracle
Command Type)
lid
用于安全性检查访问权限的用户ID
tim
定时器,1/100秒
ha
SQL语句的哈希ID
ad
V$SQLAREA中此SQL语句的ADDR列
EXEC
Cursor#:c=%d,e=%d,p=%d,cr=%d,mis=%d,r=%d,dep=%d,og=%d,tim=%d
Cursor #
游标号
c
CPU时间,1/100秒
e
流逝(Elapsed)时间,1/100秒
p
物理读
cr
一致(QUERY模式)读(逻辑I/O)
cu
当前(Current)模式读(逻辑I/O)
mis
字典缓存中的游标不命中数,说明由于过期已从共享池中清除或从未进入共享池等,而不得不分析此语句
r
处理的行数
dep
SQL语句的递归深度
og
优化器目标:1=ALL ROWS
2=FIRST ROWS 3=RULE
4=CHOOSE
tim
定时器
与EXEC段类似的还有(即取代“EXEC”):
PARSE
分析一个语句
FETCH
从一个游标取出数据行
UNMAP
用于显示在不需要时从中间结果释放临时段
SORT UMAP
同UNMAP,指排序段
WAIT Cursor#: nam=’%s’ ela=%d p1=%ul p2=%ul
p3=%ul
Cursor#
游标号
nam
等待事件名
ela
流逝时间,1/100秒
p1,p2,p3
等待事件特定的参数
以上为文件头与ALTER
SESSION出现的跟踪信息。此后开始出现运行的SQL语句。
BIND段
cursor#
游标号
bind N
绑定位置,从0开始
dty
数据类型
mxl
绑定变量最大长度
mal
最大数组长度(当使用数组绑定或BULK操作时)
scl
数值范围(scale)
pre
精度(precision)
oacflg
内部标记。若此值为奇数,则绑定变量可能为NULL(允许为NULL)
oacfl2
内部标记续
size
缓冲区大小
offset
用于逐片(piecewise)绑定
bfp