oracle 执行计划学习

写好一段SQL代码以后,可以通过查看SQL的执行计划,初步预测该SQL在运行时的性能好坏,尤其是在SQL调优的时候,可以通过查看执行计划,来分析SQL性能问题

选中要执行的SQL,按F5,或者点击”执行计划”图标,会自动打开执行计划窗口,显示该SQL的执行计划.

<img src="https://img-blog.csdn.net/20160904160252415?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />

窗口上方是sql 语句,下方显示执行表格计划,表格的列主要包含描述,用户,对象,成本花费,IO 开销等, 表格,表格还可以自定义列,表格的行包含了查询逻辑的执行顺序和各个步骤信息

执行计划表格内容的执行顺序是: 按照从左到右,从上到下的步骤执行,具体是指执行计划按照层次逐步缩进,从左到右看,缩进最多的那一步最先执行,如果缩进量相同,则按照从上到下的方法判断执行顺序[先左右》后上下]

通过查看执行计划表格的cost列,即成本花费能够知道哪个步骤花费的成本高,通过查看执行计划表格的行中的objectName 列, 能够知道是否使用到表中的索引

----  索引基本知识
首先数据量小的表不需要建立索引,因为小的表即使建立索引也不会有大的用处,还会增加额外的索引开销
不经常引用的列不要建立索引,因为不常用,即使建立了索引页没有多大意义
经常频繁更新的列不要建立索引,因为肯定会影响插入或者更新的效率
索引并不是一劳永逸的,用的时间长了需要进行整理或者重建

---  oracle 高水位基本问题
所有的oracle 段(segments 建议把segment作为表的一个同义词) 都有一个在段内容纳数据的上限,我们把这个上限称为high water mark 或者 HWM, 这个HWM 是一个标记,用来说明已经有多少没有使用的数据块分配给这个segment ,HWM 通常增长的幅度为一次5个数据块,原则上HWM 只会增大不会缩小,即使把表的数据全部删除,HWM 还会为原值,由于这个特点,使得HWM 很像一个水库的历史最高水位线,这就是高水位的原始含义,当然不能说一个水库没水了,就说明该水库的历史最高水位为0,但是如果在表上使用了truncate 命令,则该表的 HWM 会被重新布置为0 

高水位对数据库操作的影响
A)全表扫描通常要读出直到HWM标记的所有属于该表的数据块,即使该表中没有任何数据
B)即使HWM 以下有空闲的数据块, 但还是建议插入数据时候使用 append 关键字,此时插入时会使用HWM 以上的数据块,此时 HWM 会自动增大
在存储过程中通常使用以下两个关键字 APPEND NOLOGGING
Insert  /*APPEND*/ into table1 nologging
这两个关键字起什么作用呢?
APPEND 提示 Oracle 使用快速机制来插入数据,意思是说将数据直接插入到表的最后,可以提高操作速度
NOLOGGING 是不将操作记录录入redo 日志,也可以提高速度

-- oracle redo日志
Redo, 也就是在必要的时候重新做,什么时候必须做呢? 那就是在系统故障的时候
因为数据库缓冲的原因,对磁盘数据的更新并不是实时的,但是redo日志的更新确实是在commit的时候肯定发生的
系统一旦写入了redo 日志,则可以确认事务已经提交,然后系统会在合适的时候更新磁盘数据记录;
果此时刚好系统故障,比如断电,在系统重启后,会读取以前的磁盘数据,然后查看redo日志,将那些已经写入redo日志,但没有更新磁盘的内容【重做】,这样就恢复到了系统故障前的那个点上。

索引有时候不能使用可以以下语句解决下
analyze table TABLENAME compute statistics
Analyze table TABLENAME estimate statistics sample 50 percent

如何知道一个表的 HWM 
首先对表进行分析
Analyze table TABLENAME ESTIMATE/COMPUTE STATISTICS
Select blocks ,empty_blocks,num_rows from user_tables where table_name = TABLENAME
BLOCKS 列代表该表中曾经使用过得数据库块的数目,即水线。
EMPTY_BLOCKS 代表分配给该表,但是在水线以上的数据库块,即从来没有使用的数据块。

SELECT segment_name, segment_type, blocks FROM dba_segments WHERE segment_name='BIG_EMP1'
ANALYZE TABLE big_emp1 ESTIMATE STATISTICS;
SELECT table_name,num_rows,blocks,empty_blocks
FROM user_tables
WHERE table_name='BIG_EMP1';
TRUNCATE命令回收了由delete命令产生的空闲空间,注意该表分配的空间由原先的1024块降为512块。
为了保留由delete命令产生的空闲空间,可以使用TRUNCATE TABLE big_emp1 REUSE STORAGE.
用此命令后,该表还会是原先的1024块。
这条高水位线在日常的增删操作中只会上涨,不会下跌。

下面我们来谈一下Oracle中Select语句的特性。Select语句会对表中的数据进行一次扫描,但是究竟扫描多少数据存储块呢,这个并不是说数据库中有多少数据,Oracle就扫描这么大的数据块,而是Oracle会扫描高水位线以下的数据块。现在来想象一下,如果刚才是一张刚刚建立的空表,你进行了一次Select操作,那么由于高水位线HWM在最低的0位置上,所以没有数据块需要被扫描,扫描时间会极短。而如果这个时候你首先插入了一千万条数据,然后再用delete语句删除这一千万条数据。由于插入了一千万条数据,所以这个时候的高水位线就在一千万条数据这里。后来删除这一千万条数据的时候,由于delete语句不影响高水位线,所以高水位线依然在一千万条数据这里。这个时候再一次用select语句进行扫描,虽然这个时候表中没有数据,但是由于扫描是按照高水位线来的,所以需要把一千万条数据的存储空间都要扫描一次,也就是说这次扫描所需要的时间和扫描一千万条数据所需要的时间是一样多的。所以有时候有人总是经常说,怎么我的表中没有几条数据,但是还是这么慢呢,这个时候其实奥秘就是这里的高水位线了。
那有没有办法让高水位线下降呢,其实有一种比较简单的方法,那就是采用TRUNCATE语句进行删除数据。采用TRUNCATE语句删除一个表的数据的时候,类似于重新建立了表,不仅把数据都删除了,还把HWM给清空恢复为0。所以如果需要把表清空,在有可能利用TRUNCATE语句来删除数据的时候就利用TRUNCATE语句来删除表,特别是那种数据量有可能很大的临时存储表。
在oracle中,执行对表的删除操作不会降低该表的高水位线,而全表扫描将始终读取一个段中所有低于高水位线标记的块,如果在执行删除操作后不降低高水位线标记,则将导致查询语句的性能低下,下面的方法都可以降低高水位线标记;
1 执行表的重建指令 alter table TABLENAME move;
2 alter table TABLENAME shrink space;
3.复制要保留的数据到临时表t,drop原表,然后rename临时表t为原表
4.emp/imp
5.alter   table  table_name  deallocate   unused  
6.尽量truncate吧
一个SQL查询用不到索引,classid是建了索引的,如下:
select * from infobase where classid in(10001,10002,10003,10004,10005);
奇怪的发现在classid in(10001,10002)的值两以上就用不索引,两个以下就可以用到,开始怀疑是索引有问题,于是就重建下了下classid上的索引还是不行。从网上找到一篇文章才知道可能是表中存在碎片的问题
于是用下面的步骤解决:
1、重建表:
create table infobase2 select * from infobase;
2、改以前的表名:
alter table infobase rename to infobase3;
3、改新建表名为以前表名:
alter table infobase2 rename to infobase;
4、建上索引:
create index classid_ind on infobase(classid);
可是过了一天问题又出现了,索引又是不能使用了,然后执行下面的语句解决:
ANALYZE TABLE INFOBASE compute Statistics;
或是
ANALYZE TABLE INFOBASE estimate STATISTICS SAMPLE 50 PERCENT ;
--注意:50 PERCENT 值太小索引可能还是不起作用,我就开始用20 PERCENT 时,索引还是用不上。


-- oracle RBO CBO 
Rule based optimizer RBO 基于规则
Cost based optimizer CBO 基于成本 或者讲统计信息
Oracle 提供了CBO RBO 两种 SQL 优化器,CBO在oracle7 引入,但是在oracle8i 中才成熟,oracle已经明确声明在oracle9i 之后的版本中RBO将不再支持,因此选择CBO 是必然的趋势;
CBO 和 RBO 作为不同的 SQL 优化器,对SQL 语句的执行计划产生重大影响,如果要对现有的应用程序从RBO 向 CBO 移植,则必须充分考虑这些影响,避免SQL 语句性能急剧下降,但是,对新的应用系统,则可以考虑直接使用CBO, 在CBO模式下进行SQL 语句编写,分析执行计划,性能测试等工作,这需要开发者对CBO的特性比较熟悉,以下小结几点在CBO下写SQL语句的注意事项

1 RBO 自oracle 6版本来被采用,有着一套严格的使用规则,只要按照它去写SQL语句,无论数据表的内容怎样,也不会影响你的”执行计划”,也就是说对数据部敏感,CBO计算各种可能”执行计划的代价”,即cost,从中选用cost 最低方案,作为实际运行方案,各”执行计划”的cost的计算根据,依赖于数据表中数据的统计分布,oracle数据库本身对该统计分布并不清楚,必须要分析表和相关的索引(使用analyze命令),才能搜集到CBO所需要的数据;

使用CBO 时,编写SQL语句时,不必考虑"FROM" 子句后面的表或视图的顺序和"WHERE" 子句后面的条件顺序;ORACLE自7版以来采用的许多新技术都是基于CBO的,如星型连接排列查询,哈希连接查询,函数索引,和并行查询等

一般而言,CBO所选择的“执行计划”都不会比RBO的“执行计划”差,而且相对而言,CBO对程序员的要求没有RBO那么苛刻,节省了程序员为了从多个可能的“执行计划”中选择一个最优的方案而花费的调试时间,但在某些场合下也会存在问题。较典型的问题有:有时,表明明建有索引,但查询过程显然没有用到相关的索引,导致查询过程耗时漫长,占用资源巨大,这时就需要仔细分析执行计划,找出原因。例如,可以看连接顺序是否允许使用相关索引。假设表emp的deptno列上有索引,表dept的列deptno上无索引,WHERE语句有emp.deptno=dept.deptno条件。在做NL连接时,emp做为外表,先被访问,由于连接机制原因,外表的数据访问方式是全表扫描,emp.deptno上的索引显然是用不上,最多在其上做索引全扫描或索引快速全扫描。

如果一个语句使用 RBO的执行计划确实比CBO 好,则可以通过加 " rule" 提示,强制使用RBO

使用CBO 时,SQL语句 "FROM" 子句后面的表,必须全部使用ANALYZE 命令分析过,如果"FROM" 子句后面的是视图,则此视图的基础表,也必须全部使用ANALYZE 命令分析过;否则,ORACLE 会在执行此SQL语句之前,自动进行ANALYZE 命令分析,这会极大导致SQL语句执行极其缓慢

使用CBO 时,SQL语句 "FROM" 子句后面的表的个数不宜太多,因为CBO在选择表连接顺序时,会对"FROM" 子句后面的表进行阶乘运算,选择最好的一个连接顺序。假如"FROM" 子句后有6个表,则其可选择的连接顺序就是6*5*4*3*2*1 = 720 种,CBO 选择其中一种,而如果"FROM" 子句后有12个表,则其可选择的连接顺序就是12*11*10*9*8*7*6*5*4*3*2*1= 479001600 种,可以想象从中选择一种,会消耗多少CPU 时间?如果实在是要访问很多表,则最好使用 ORDER 提示,强制使用"FROM" 子句表固定的访问顺序。
/*+ORDERED*/根据表出现在FROM中的顺序,ORDERED使ORACLE依此顺序对其连接.
SELECT /*+ORDERED*/ A.COL1,B.COL2,C.COL3 FROM TABLE1 A,TABLE2 B,TABLE3 C WHERE A.COL1=B.COL1 AND B.COL1=C.COL1;

使用CBO 时,SQL语句中不能引用系统数据字典表或视图,因为系统数据字典表都未被分析过,可能导致极差的“执行计划”。但是不要擅自对数据字典表做分析,否则可能导致死锁,或系统性能严重下降

使用CBO 时,要注意看采用了哪种类型的表连接方式。ORACLE的共有Sort Merge Join(SMJ)、Hash Join(HJ)和Nested Loop Join(NL)。CBO有时会偏重于SMJ 和 HJ,但在OLTP 系统中,NL 一般会更好,因为它高效的使用了索引。在两张表连接,且内表的目标列上建有索引时,只有Nested Loop才能有效地利用到该索引。SMJ即使相关列上建有索引,最多只能因索引的存在,避免数据排序过程。HJ由于须做HASH运算,索引的存在对数据查询速度几乎没有影响。

使用CBO 时,必须保证为表和相关的索引搜集足够的统计数据。对数据经常有增、删、改的表最好定期对表和索引进行分析,可用SQL语句“analyze table xxx compute statistics for all indexes;"ORACLE掌握了充分反映实际的统计数据,才有可能做出正确的选择

使用CBO 时,要注意被索引的字段的值的数据分布,会影响SQL语句的执行计划。例如:表emp,共有一百万行数据,但其中的emp.deptno列,数据只有4种不同的值,如10、20、30、40。虽然emp数据行有很多,ORACLE缺省认定表中列的值是在所有数据行均匀分布的,也就是说每种deptno值各有25万数据行与之对应。假设SQL搜索条件DEPTNO=10,利用deptno列上的索引进行数据搜索效率,往往不比全表扫描的高,ORACLE理所当然对索引“视而不见”,认为该索引的选择性不高

我们考虑另一种情况,如果一百万数据行实际不是在4种deptno值间平均分配,其中有99万行对应着值10,5000行对应值20,3000行对应值30,2000行对应值40。在这种数据分布图案中对除值为10外的其它deptno值搜索时,毫无疑问,如果索引能被应用,那么效率会高出很多。我们可以采用对该索引列进行单独分析,或用analyze语句对该列建立直方图,对该列搜集足够的统计数据,使ORACLE在搜索选择性较高的值能用上索引。















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值