第四部分、性能调整
[Q]
如果设置自动跟踪
[A]
用
system
登录
执行
$ORACLE_HOME/rdbms/admin/utlxplan.sql
创建计划表
执行
$ORACLE_HOME/sqlplus/admin/plustrce.sql
创建
plustrace
角色
如果想计划表让每个用户都能使用,则
SQL>create public synonym plan_table for plan_table;
SQL> grant all on plan_table to public;
如果想让自动跟踪的角色让每个用户都能使用,则
SQL> grant plustrace to public;
通过如下语句开启
/
停止跟踪
SET AUTOTRACE ON |OFF
| ON EXPLAIN | ON STATISTICS | TRACEONLY | TRACEONLY EXPLAIN
[Q]
如果跟踪自己的会话或者是别人的会话
[A]
跟踪自己的会话很简单
Alter session set sql_trace true|false
Or
Exec dbms_session.set_sql_trace(TRUE);
如果跟踪别人的会话,需要调用一个包
exec dbms_system.set_sql_trace_in_session(sid,serial#,true|false)
跟踪的信息在
user_dump_dest
目录下可以找到或通过如下脚本获得文件名称(适用于
Win
环境,如果是
unix
需要做一定修改)
SELECT p1.value||'\'||p2.value||'_ora_'||p.spid||'.ora' filename
FROM
v$process p,
v$session s,
v$parameter p1,
v$parameter p2
WHERE p1.name = 'user_dump_dest'
AND p2.name = 'db_name'
AND p.addr = s.paddr
AND s.audsid = USERENV ('SESSIONID')
最后,可以通过
Tkprof
来解析跟踪文件,如
Tkprof
原文件
目标文件
sys=n
[Q]
怎么设置整个数据库系统跟踪
[A]
其实文档上的
alter system set sql_trace=true
是不成功的
但是可以通过设置事件来完成这个工作,作用相等
alter system set events
'10046 trace name context forever,level 1';
如果关闭跟踪,可以用如下语句
alter system set events
'10046 trace name context off';
其中的
level 1
与上面的
8
都是跟踪级别
level 1
:跟踪
SQL
语句,等于
sql_trace=true
level 4
:包括变量的详细信息
level 8
:包括等待事件
level 12
:包括绑定变量与等待事件
[Q]
怎么样根据
OS
进程快速获得
DB
进程信息与正在执行的语句
[A]
有些时候,我们在
OS
上操作,象
TOP
之后我们得到的
OS
进程,怎么快速根据
OS
信息获得
DB
信息呢?
我们可以编写如下脚本:
$more whoit.sh
#!/bin/sh
sqlplus /nolog <<EOF
connect / as sysdba
col machine format a30
col program format a40
set line 200
select sid,serial# ,username,osuser,machine,program,process,to_char(logon_time,'yyyy/mm/dd hh24:mi:ss')
from v\$session where paddr in
( select addr from v\$process where spid in($1));
select sql_text from v\$sqltext_with_newlines
where hash_value in
(select SQL_HASH_value from v\$session where
paddr in (select addr from v\$process where spid=$1)
)
order by piece;
exit;
EOF
然后,我们只要在
OS
环境下如下执行即可
$./whoit.sh Spid
[Q]
怎么样分析表或索引
[A]
命令行方式可以采用
analyze
命令
如
Analyze table tablename compute statistics;
Analyze index|cluster indexname estimate statistics;
ANALYZE TABLE tablename COMPUTE STATISTICS
FOR TABLE
FOR ALL [LOCAL] INDEXES
FOR ALL [INDEXED] COLUMNS;
ANALYZE TABLE tablename DELETE STATISTICS
ANALYZE TABLE tablename VALIDATE REF UPDATE
ANALYZE TABLE tablename VALIDATE STRUCTURE
[CASCADE]|[INTO TableName]
ANALYZE TABLE tablename LIST CHAINED ROWS [INTO TableName]
等等。
如果想分析整个用户或数据库,还可以采用工具包,可以并行分析
Dbms_utility(8i
以前的工具包
)
Dbms_stats(8i
以后提供的工具包
)
如
dbms_stats.gather_schema_stats(User,estimate_percent=>100,cascade=> TRUE);
dbms_stats.gather_table_stats(User,TableName,degree => 4,cascade => true);
这是对命令与工具包的一些总结
1
、对于分区表,建议使用
DBMS_STATS
,而不是使用
Analyze
语句。
a)
可以并行进行,对多个用户,多个
Table
b)
可以得到整个分区表的数据和单个分区的数据。
c)
可以在不同级别上
Compute Statistics
:单个分区,子分区,全表,所有分区
d)
可以倒出统计信息
e)
可以用户自动收集统计信息
2
、
DBMS_STATS
的缺点
a)
不能
Validate Structure
b)
不能收集
CHAINED ROWS,
不能收集
CLUSTER TABLE
的信息,这两个仍旧需要使用
Analyze
语句。
c) DBMS_STATS
默认不对索引进行
Analyze
,因为默认
Cascade
是
False
,需要手工指定为
True
3
、对于
oracle 9
里面的
External Table
,
Analyze
不能使用,只能使用
DBMS_STATS
来收集信息。
[Q]
怎么样快速重整索引
[A]
通过
rebuild
语句,可以快速重整或移动索引到别的表空间
rebuild
有重建整个索引数的功能,可以在不删除原始索引的情况下改变索引的存储参数
语法为
alter index index_name rebuild tablespace ts_name
storage(……);
如果要快速重建整个用户下的索引,可以用如下脚本,当然,需要根据你自己的情况做相应修改
SQL> set heading off
SQL> set feedback off
SQL> spool d:\index.sql
SQL> SELECT 'alter index ' || index_name || ' rebuild '
||'tablespace INDEXES storage(initial 256K next 256K pctincrease 0);'
FROM all_indexes
WHERE ( tablespace_name != 'INDEXES'
OR next_extent != ( 256 * 1024 )
)
AND owner = USER
SQL>spool off
另外一个合并索引的语句是
alter index index_name coalesce
,这个语句仅仅是合并索引中同一级的
leaf block
消耗不大,对于有些索引中存在大量空间浪费的情况下,有一些作用。
[Q]
如何使用
Hint
提示
[A]
在
select/delete/update
后写
/*+ hint */
如
select /*+ index(TABLE_NAME INDEX_NAME) */ col1...
注意
/*
和
+
之间不能有空格
如用
hint
指定使用某个索引
select /*+ index(cbotab) */ col1 from cbotab;
select /*+ index(cbotab cbotab1) */ col1 from cbotab;
select /*+ index(a cbotab1) */ col1 from cbotab a;
其中
TABLE_NAME
是必须要写的,且如果在查询中使用了表的别名,在
hint
也要用表的别名来代替表名
;
INDEX_NAME
可以不必写,
Oracle
会根据统计值选一个索引
;
如果索引名或表名写错了,那这个
hint
就会被忽略
;
[Q]
怎么样快速复制表或者是插入数据
[A]
快速复制表可以指定
Nologging
选项
如:
Create table t1 nologging
as select * from t2;
快速插入数据可以指定
append
提示,但是需要注意
noarchivelog
模式下,默认用了
append
就是
nologging
模式的。
在
archivelog
下,需要把表设置程
Nologging
模式。
如
insert /*+ append */ into t1
select * from t2
注意:如果在
9i
环境中并设置了
FORCE LOGGING
,则以上操作是无效的,并不会加快,当然,可以通过如下语句设置为
NO FORCE LOGGING
。
Alter database no force logging;
是否开启了
FORCE LOGGING
,可以用如下语句查看
SQL> select force_logging from v$database;
[Q]
怎么避免使用特定索引
[A]
在很多时候,
Oracle
会错误的使用索引而导致效率的明显下降,我们可以使用一点点技巧而避免使用不该使用的索引,如:
表
test,
有字段
a,b,c,d
,在
a,b,c
上建立联合索引
inx_a(a,b,c)
,在
b
上单独建立了一个索引
Inx_b(b)
。
在正常情况下,
where a=? and b=? and c=?
会用到索引
inx_a
,
where b=?
会用到索引
inx_b
但是,
where a=? and b=? and c=? group by b
会用到哪个索引呢?在分析数据不正确(很长时间没有分析)或根本没有分析数据的情况下,
oracle
往往会使用索引
inx_b
。通过执行计划的分析,这个索引的使用,将大大耗费查询时间。
当然,我们可以通过如下的技巧避免使用
inx_b
,而使用
inx_a
。
where a=? and b=? and c=? group by b||'' --
如果
b
是字符
where a=? and b=? and c=? group by b+0 --
如果
b
是数字
通过这样简单的改变,往往可以是查询时间提交很多倍
当然,我们也可以使用
no_index
提示,相信很多人没有用过,也是一个不错的方法:
select /*+ no_index(t,inx_b) */ * from test t
where a=? and b=? and c=? group by b
[Q]Oracle
什么时候会使用跳跃式索引扫描
[A]
这是
9i
的一个新特性跳跃式索引扫描
(Index Skip Scan).
例如表有索引
index(a,b,c)
,当查询条件为
where b=?
的时候,可能会使用到索引
index(a,b,c)
如,执行计划中出现如下计划:
INDEX (SKIP SCAN) OF 'TEST_IDX' (NON-UNIQUE)
Oracle
的优化器
(
这里指的是
CBO)
能对查询应用
Index Skip Scans
至少要有几个条件
:
1
优化器认为是合适的。
2
索引中的前导列的唯一值的数量能满足一定的条件(如重复值很多)。
3
优化器要知道前导列的值分布
(
通过分析
/
统计表得到
)
。
4
合适的
SQL
语句
等。
[Q]
怎么样创建使用虚拟索引
[A]
可以使用
nosegment
选项,如
create index virtual_index_name on table_name(col_name) nosegment;
如果在哪个
session
需要测试虚拟索引,可以利用隐含参数来处理
alter session set "_use_nosegment_indexes" = true;
就可以利用
explain plan for select ……
来看虚拟索引的效果
利用
@$ORACLE_HOME/rdbms/admin/utlxpls
查看执行计划
最后,根据需要,我们可以删除虚拟索引,如普通索引一样
drop index virtual_index_name;
注意:虚拟索引并不是物理存在的,所以虚拟索引并不等同于物理索引,不要用自动跟踪去测试虚拟索引,因为那是实际执行的效果,是用不到虚拟索引的。
[Q]
怎样监控无用的索引
[A]Oracle 9i
以上,可以监控索引的使用情况,如果一段时间内没有使用的索引,一般就是无用的索引
语法为:
开始监控:
alter index index_name monitoring usage;
检查使用状态:
select * from v$object_usage;
停止监控:
alter index index_name nomonitoring usage;
当然,如果想监控整个用户下的索引,可以采用如下的脚本:
set heading off
set echo off
set feedback off
set pages 10000
spool start_index_monitor.sql
SELECT 'alter index '||owner||'.'||index_name||' monitoring usage;'
FROM dba_indexes
WHERE owner = USER;
spool off
set heading on
set echo on
set feedback on
------------------------------------------------
set heading off
set echo off
set feedback off
set pages 10000
spool stop_index_monitor.sql
SELECT 'alter index '||owner||'.'||index_name||' nomonitoring usage;'
FROM dba_indexes
WHERE owner = USER;
spool off
set heading on
set echo on
set feedback on
[Q]
怎么样能固定我的执行计划
[A]
可以使用
OUTLINE
来固定
SQL
语句的执行计划
用如下语句可以创建一个
OUTLINE
Create oe replace outline OutLn_Name on
Select Col1,Col2 from Table
where ……
如果要删除
Outline
,可以采用
Drop Outline OutLn_Name;
对于已经创建了的
OutLine
,存放在
OUTLN
用户的
OL$HINTS
表下面
对于有些语句,你可以使用
update outln.ol$hints
来更新
outline
如
update outln.ol$hints(ol_name,'TEST1','TEST2','TEST2','TEST1)
where ol_name in ('TEST1','TEST2');
这样,你就把
Test1 OUTLINE
与
Test2 OUTLINE
互换了
如果想利用已经存在的
OUTLINE
,需要设置以下参数
Alter system/session set Query_rewrite_enabled = true
Alter system/session set use_stored_outlines = true
[Q]v$sysstat
中的
class
分别代表什么
[A]
统计类别
1
代表事例活动
2
代表
Redo buffer
活动
4
代表锁
8
代表数据缓冲活动
16
代表
OS
活动
32
代表并行活动
64
代表表访问
128
代表调试信息
[Q]
怎么杀掉特定的数据库会话
[A] Alter system kill session 'sid,serial#';
或者
alter system disconnect session 'sid,serial#' immediate;
在
win
上,还可以采用
oracle
提供的
orakill
杀掉一个线程(其实就是一个
Oracle
进程)
在
Linux/Unix
上,可以直接利用
kill
杀掉数据库进程对应的
OS
进程
[Q]
怎么快速查找锁与锁等待
[A]
数据库的锁是比较耗费资源的,特别是发生锁等待的时候,我们必须找到发生等待的锁,有可能的话,杀掉该进程。
这个语句将查找到数据库中所有的
DML
语句产生的锁,还可以发现,任何
DML
语句其实产生了两个锁,一个是表锁,一个是行锁。
可以通过
alter system kill session ‘sid,serial#’
来杀掉会话
SELECT /*+ rule */ s.username,
decode(l.type,'TM','TABLE LOCK',
'TX','ROW LOCK',
NULL) LOCK_LEVEL,
o.owner,o.object_name,o.object_type,
s.sid,s.serial#,s.terminal,s.machine,s.program,s.osuser
FROM v$session s,v$lock l,dba_objects o
WHERE l.sid = s.sid
AND l.id1 = o.object_id(+)
AND s.username is NOT NULL
如果发生了锁等待,我们可能更想知道是谁锁了表而引起谁的等待
以下的语句可以查询到谁锁了表,而谁在等待。
SELECT /*+ rule */ lpad(' ',decode(l.xidusn ,0,3,0))||l.oracle_username User_name,
o.owner,o.object_name,o.object_type,s.sid,s.serial#
FROM v$locked_object l,dba_objects o,v$session s
WHERE l.object_id=o.object_id
AND l.session_id=s.sid
ORDER BY o.object_id,xidusn DESC
以上查询结果是一个树状结构,如果有子节点,则表示有等待发生。如果想知道锁用了哪个回滚段,还可以关联到
V$rollname
,其中
xidusn
就是回滚段的
USN
[Q]
如何有效的删除一个大表
(extent
数很多的表
)
[A]
一个有很多
(100k)extent
的表,如果只是简单地用
drop table
的话,会很大量消耗
CPU
(
Oracle
要对
fet$
、
uet$
数据字典进行操作),可能会用上几天的时间,较好的方法是分多次删除
extent
,以减轻这种消耗:
1. truncate table big-table reuse storage;
2. alter table big-table deallocate unused keep 2000m (
原来大小的
n-1/n);
3. alter table big-table deallocate unused keep 1500m ;
....
4. drop table big-table;
[Q]
如何收缩临时数据文件的大小
[A]9i
以下版本采用
ALTER DATABASE DATAFILE 'file name' RESIZE 100M
类似的语句
9i
以上版本采用
ALTER DATABASE TEMPFILE 'file name' RESIZE 100M
注意,临时数据文件在使用时,一般不能收缩,除非关闭数据库或断开所有会话,停止对临时数据文件的使用。
[Q]
怎么清理临时段
[A]
可以使用如下办法
1
、
使用如下语句查看一下认谁在用临时段
SELECT username,sid,serial#,sql_address,machine,program,
tablespace,segtype, contents
FROM v$session se,v$sort_usage su
WHERE se.saddr=su.session_addr
2
、
那些正在使用临时段的进程
SQL>Alter system kill session 'sid,serial#';
3
、把
TEMP
表空间回缩一下
SQL>Alter tablespace TEMP coalesce;
还可以使用诊断事件
1
、
确定
TEMP
表空间的
ts#
SQL> select ts#, name FROM v$tablespace;
TS# NAME
-----------------------
0 SYSYEM
1 RBS
2 USERS
3* TEMP
……
2
、
执行清理操作
alter session set events 'immediate trace name DROP_SEGMENTS level TS#+1'
说明:
temp
表空间的
TS#
为
3*, So TS#+ 1= 4
如果想清除所有表空间的临时段,则
TS# = 2147483647
[Q]
怎么样
dump
数据库内部结构,如上面显示的控制文件的结构
[A]
常见的有
1
、分析数据文件块,转储数据文件
n
的块
m
alter system dump datafile n block m
2
、分析日志文件
alter system dump logfile logfilename;
3
、分析控制文件的内容
alter session set events 'immediate trace name CONTROLF level 10'
4
、分析所有数据文件头
alter session set events 'immediate trace name FILE_HDRS level 10'
5
、分析日志文件头
alter session set events 'immediate trace name REDOHDR level 10'
6
、分析系统状态,最好每
10
分钟一次,做三次对比
alter session set events 'immediate trace name SYSTEMSTATE level 10'
7
、分析进程状态
alter session set events 'immediate trace name PROCESSSTATE level 10'
8
、分析
Library Cache
的详细情况
alter session set events 'immediate trace name library_cache level 10'
[Q]
如何获得所有的事件代码
[A]
事件代码范围一般从
10000 to 10999
,以下列出了这个范围的事件代码与信息
SET SERVEROUTPUT ON
DECLARE
err_msg VARCHAR2(120);
BEGIN
dbms_output.enable (1000000);
FOR err_num IN 10000..10999
LOOP
err_msg := SQLERRM (-err_num);
IF err_msg NOT LIKE '%Message '||err_num||' not found%' THEN
dbms_output.put_line (err_msg);
END IF;
END LOOP;
END;
/
在
Unix
系统上,事件信息放在一个文本文件里
$ORACLE_HOME/rdbms/mesg/oraus.msg
可以用如下脚本查看事件信息
event=10000
while [ $event -ne 10999 ]
do
event=`expr $event + 1`
oerr ora $event
done
对于已经确保的
/
正在跟踪的事件,可以用如下脚本获得
SET SERVEROUTPUT ON
DECLARE
l_level NUMBER;
BEGIN
FOR l_event IN 10000..10999
LOOP
dbms_system.read_ev (l_event,l_level);
IF l_level > 0 THEN
dbms_output.put_line ('Event '||TO_CHAR (l_event)||
' is set at level '||TO_CHAR (l_level));
END IF;
END LOOP;
END;
/
[Q]
什么是
STATSPACK
,我怎么使用它?
[A]Statspack
是
Oracle 8i
以上提供的一个非常好的性能监控与诊断工具,基本上全部包含了
BSTAT/ESTAT
的功能,更多的信息
可以参考附带文档
$ORACLE_HOME/rdbms/admin/spdoc.txt
。
安装
Statspack:
cd $ORACLE_HOME/rdbms/admin
sqlplus "/ as sysdba" @spdrop.sql --
卸载,第一次可以不需要
sqlplus "/ as sysdba" @spcreate.sql --
需要根据提示输入表空间名
使用
Statspack:
sqlplus perfstat/perfstat
exec statspack.snap; --
进行信息收集统计,每次运行都将产生一个快照号
--
获得快照号,必须要有两个以上的快照,才能生成报表
select SNAP_ID, SNAP_TIME from STATS$SNAPSHOT;
@spreport.sql --
输入需要查看的开始快照号与结束快照号
其他相关脚本
s:
spauto.sql -
利用
dbms_job
提交一个作业,自动的进行
STATPACK
的信息收集统计
sppurge.sql -
清除一段范围内的统计信息,需要提供开始快照与结束快照号
sptrunc.sql -
清除
(truncate)
所有统计信