oracle 优化相关

--选择最有效率的表名顺序:
  Oracle的解析器按照从右到左的顺序处理FROM子句中的表名,FROM子句中写在最后的表(基础表 driving table)将被最先处理,
  在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表。如果有3个以上的表连接查询,
  那就需要选择交叉表(intersection table)作为基础表, 交叉表是指那个被其他表所引用的表。
--WHERE子句中的连接顺序: 
  Oracle采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前, 那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾。
 
--select 子句中避免使用*
  Oracle在解析的过程中, 会将‘*’依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间
 
--用Where子句替换HAVING子句
  HAVING 只会在检索出所有记录之后才对结果集进行过滤,而Where子句在检索时过滤
  on、where、having这三个都可以加条件的子句中,on是最先执行,where次之,having最后
 
--用EXISTS替代IN、用NOT EXISTS替代NOT IN
  在许多基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接。在这种情况下,使用EXISTS(或NOT EXISTS)通常将提高查询的效率。
  在子查询中,NOT IN子句将执行一个内部的排序和合并。无论在哪种情况下,NOT IN都是最低效的 (因为它对子查询中的表执行了一个全表遍历)。
  为了避免使用NOT IN ,我们可以把它改写成外连接(Outer Joins)或NOT EXISTS。
 
--SQL语句用大写的;因为Oracle总是先解析SQL语句,把小写的字母转换成大写的再执行。 

--在Java代码中尽量少用连接符“+”连接字符串。
  一个'+'就会产生一个新对象
 
--用>=替代>:
  高效:SELECT * FROM EMP WHERE DEPTNO >=4 低效: SELECT * FROM EMP WHERE DEPTNO >3
  两者的区别在于,前者DBMS将直接跳到第一个DEPT等于4的记录而后者将首先定位到DEPTNO=3的记录并且向前扫描到第一个DEPT大于3的记 录。
 
--避免在索引列上使用NOT、IS NULL和IS NOT NULL:
  NOT会产生在和在索引列上使用函数相同的影响。当Oracle“遇到”NOT、IS NULL和IS NOT NULL,他就会停止使用索引转而执行全表扫描。
 
--避免在索引列上使用计算。
  WHERE子句中,如果索引列是函数的一部分。优化器将不使用索引而使用全表扫描。
 
  避免对索引字段进行计算操作
  避免在索引字段上使用not,<>,!=
  避免在索引列上使用IS NULL和IS NOT NULL
  避免在索引列上出现数据类型转换
  避免在索引字段上使用函数
  避免建立索引的列中使用空值。

--用UNION替换OR (适用于索引列):
  通常情况下,用UNION替换WHERE子句中的OR将会起到较好的效果。对索引列使用OR将造成全表扫描。
  注意,以上规则只针对多个索引列有效。如果有 column没有被索引,查询效率可能会因为你没有选择OR而降低。

--总是使用索引的第一个列: 
  如果索引是建立在多个列上,只有在它的第一个列(leading column)被where子句引用时,优化器才会选择使用该索引。
  这也是一条简单而重要的规则,当仅引用索引的第二个列时,优化器使用了全表扫描而忽略 了索引。 

--‘||'是字符连接函数、‘+'是数学函数。就象其他函数那样, 停用了索引。 

--相同的索引列不能互相比较,这将会启用全表扫描。 

--模糊查询like
 %yue%,由于yue前面用到了“%”,因此该查询必然走全表扫描,除非必要,否则不要在关键词前加%。                               


--不要以字符格式声明数字,要以数字格式声明字符值。(日期同样)否则会使索引无效,产生全表扫描
 使用    :SELECT emp.ename, emp.job FROM emp WHERE emp.empno = 7369;
 不要使用:SELECT emp.ename, emp.job FROM emp WHERE emp.empno = ‘7369’

--LEFT JOIN 和 inner join
 是否真的需要left join,否则选用inner join 来减少不必要的数据返回。
 连表查询n*m,那么减少基础表的记录数目可以有效的提高效率(把查询条件放入到基础表先进行过滤,然后在进行连接)
 select top 500 * from
(select  * from  [dbo].[table1] where (ss between @a1 and @a2)) a
 LEFT JOIN  dbo.[table2] ON a.m = dbo.[table2].n
 
--应避免在where子句中使用or来连接条件,否则引擎将放弃使用索引而进行全表扫描
--应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:trim()

通过bulk collect减少loop处理的开销

采用bulk collect可以将查询结果一次性地加载到collections中。
而不是通过cursor一条一条地处理。
可以在select into,fetch into,returning into语句使用bulk collect。
注意在使用bulk collect时,所有的into变量都必须是collections.

Oracle数据库之FORALL与BULK COLLECT语句(批量处理方法):
PL/SQL块的执行过程:当PL/SQL运行时引擎处理一块代码时,
它使用PL/SQL引擎来执行过程化的代码,而将SQL语句发送给SQL引擎来执行;
SQL引擎执行完毕后,将结果再返回给PL/SQL引擎。
这种在PL/SQL引擎和SQL引擎之间的交互,称为上下文交换(context switch)。
每发生一次交换,就会带来一定的额外开销。


FORALL,用于增强PL/SQL引擎到SQL引擎的交换。
BULK COLLECT,用于增强SQL引擎到PL/SQL引擎的交换。

BULK COLLECT提供对数据的高速检索,FORALL可大大改进INSERT、UPDATE和DELETE操作的性能。
bulk collect子句用于取得批量数据,该子句只能用于select语句、fetch语句和DML返回子句,
而forall语句只适用于批发批量的DML操作。
使用FORALL,可以将多个DML批量发送给SQL引擎来执行,最大限度地减少上下文交互所带来的开销

--语法1:
FORALL 下标变量(只能当作下标被引用) IN 下限..上限
sql 语句; --只允许一条 sql 语句


--语法2:
FORALL 下标变量 IN INDICES OF(跳过没有赋值的元素,例如被 DELETE 的元素,NULL 也算值) 集合
[BETWEEN 下限 AND 上限]
sql 语句;

--indices of子句是oracle10g新增加的特征,该子句用于跳转null集合元素

--语法3:
FORALL 下标变量 IN VALUES OF 集合(把该集合中的值当作下标,且该集合值的类型只能是 PLS_INTEGER BINARY_INTEGER)
sql 语句;

在Oracle数据库10g之前,以FORAll方式使用集合有一个重要的限制:该数据库从IN范围子句中的第一行到最后一行,依次读取集合的内容

。如果在该范围内遇到一个未定义的行,Oracle数据库将引发ORA-22160异常事件:


ORA-22160: element at index [N] does not exist


对于FORALL的简单应用,这一规则不会引起任何麻烦。但是,如果想尽可能地充分利用FORALL,那么要求任意FORALL驱动数组都要依次填充可

能会增加程序的复杂性并降低性能。

在Oracle数据库10g中,PL/SQL现在在FORALL语句中提供了两个新子句:INDICES OF与VALUES OF,它们使你能够仔细选择驱动数组中该由扩展

DML语句来处理的行。

索引快速扫描(index fast full scan)
索引全扫描(INDEX FULL SCAN)
索引范围扫描(INDEX RANGE SCAN)
索引唯一扫描 (index unique scan)
索引全扫描(INDEX FULL SCAN)
索引跳跃式扫描(INDEX SKIP SCAN)

索引跳跃式扫描(INDEX SKIP SCAN)适用于所有类型的复合B树索引(包括唯一性索引和非唯一性索引),
它使那些在where条件中没有对目标索引的前导列指定查询条件但同时又对该 索引的非前导列指定了查询条件的目标SQL依然
可以用上该索引,这就像是在扫描该索引时跳过了它的前导列,直接从该索引的非前导列开始扫描一样(实际的执行过程并非如此)
,这也是索引跳跃式扫描中"跳跃"(SKIP)一词的含义。

索引全扫描 就是指要扫描目标索引所有叶子块的所有索引行

索引唯一扫描条件:索引列是唯一约束或主键、并使用“=”。

索引范围扫描(INDEX RANGE SCAN)适用于所有类型的B树索引,当扫描的对象是唯一性索引时,此时目标SQL的where条件一定是范围
查询(谓词条件为 BETWEEN、<、>等);当扫描的对象是非唯一性索引时,对目标SQL的where条件没有限制(可以是等值查询,
也可以是范围查询)。 索引范围扫描的结果可能会返回多条记录,其实这就是索引范围扫描中"范围"二字的本质含义。

索引快速全扫描与索引全扫描相比有如下三点区别。

(1)索引快速全扫描只适用于CBO。

(2)索引快速全扫描可以使用多块读,也可以并行执行。

(3)索引快速全扫描的执行结果不一定是有序的。这是因为索引快速全扫描时Oracle是根据索引行在磁盘上的物理存储顺序来扫描,
而不是根据索引行的逻辑顺序来扫描的,所以扫描结果才不一定有序(对于单个索引叶子块中的索引行而言,其物理存储顺序和逻辑
存储顺序一致;但对于物理存储位置相邻的索引叶子块而言,块与块之间索引行的物理存储顺序则不一定在逻辑上有序)。


1、避免对那些可能会产生很高的更新动作的列进行索引。
2、避免对那些经常会被删除的表中的多个列进行索引。若有可能,只对那些在这样的表上会进行删除的主关键字与/或列进行索引。如果对多个列进行索引是不可避免的,那么就应该考虑根据这些列对表进行划分,然后在每个这样的划分上执行TRUNCATE动作(而不是DELETE动作)。TRUNCATE在与 DROP STORAGE短语一同使用时,通过重新设置高水位标来模拟删除表与索引以及重新创建表与索引的过程。
3、避免为那些唯一度不高的列创建B*树索引。这样的低选择性将会导致树节点块的稠密性,从而导致由于索引“平铺( flat)”而出现的大规模索引扫描。唯一性的程度越高,性能就越好,因为这样能够减少范围扫描,甚至可能用唯一扫描来取代范围扫描。
4)空值不存储在单列索引中。对于复合索引的方式,只有当某个列不空时,才需要进行值的存储。在为DML语句创建IS NULL或IS NOT NULL短语时,应该切记这个问题。
5)IS NULL不会导致索引扫描,而一个没有带任何限制的IS NOT NULL则可能会导致完全索引扫描。

原文地址:https://www.cnblogs.com/zhonglihai/p/9874920.html