`

oracle 优化

 
阅读更多
    我们经常所说的优化,主要就是通过建立相关的索引,来提供SQL语句执行的速度.因此,如何选择索引,如何利用索引提供执行的速度就成为优化的主要任务.
 
索引无效的情况:
如果发现Oracle 在有索引的情况下,没有使用索引,这并不是Oracle 的优化器出错。在有些情况下,Oracle 确实会选择全表扫描(Full Table Scan,而非索引扫描(Index Scan)。表未做statistics, 或者 statistics 陈旧,导致 Oracle 判断失误。 
 
关于索引使用的一些误区和体会
1.      索引不是越多越好。特别是大量从来或者几乎不用的索引,对系统只有损害。OLTP系统每表超过5个索引即会降低性能,而且在一个sql 中, Oracle 从不能使用超过 5个索引。 
2.      很多时候,单列索引不如复合索引有效率。 
3.      用于多表连结的字段,加上索引会很有作用。
4.      Oracle 要使用一个索引,有一些最基本的条件: 
A.      where 子句中的这个字段,必须是复合索引的第一个字段(引导字段);
B.      where 子句中的这个字段,不应该参与任何形式的计算;
C.       where 子句中的这个字段,如果参与了函数运算,则应该建立相关的函数索引;
 
 避免在索引列上使用计算.
 WHERE子句中,如果索引列是函数的一部分.优化器将不使用索引而使用全表扫描.
避免在索引列上使用NOT
通常, 我们要避免在索引列上使用NOT, NOT会产生在和在索引列上使用函数相同的影响. 当ORACLE”遇到”NOT,他就会停止使用索引转而执行全表扫描.
>=替代>
如果DEPTNO上有一个索引,
高效:
SELECT * FROM EMP WHERE DEPTNO >=4
低效:
SELECT * FROM EMP WHERE DEPTNO >3
两者的区别在于, 前者DBMS将直接跳到第一个DEPT等于4的记录而后者将首先定位到DEPTNO=3的记录并且向前扫描到第一个DEPT大于3的记录.
 
UNION替换OR (适用于索引列)
通常情况下, 用UNION替换WHERE子句中的OR将会起到较好的效果. 对索引列使用OR将造成全表扫描. 注意, 以上规则只针对多个索引列有效. 如果有column没有被索引, 查询效率可能会因为你没有选择OR而降低.
 
 
IN来替换OR
 
避免在索引列上使用IS NULLIS NOT NULL
避免在索引中使用任何可以为空的列,ORACLE将无法使用该索引.对于单列索引,如果列包含空值,索引中将不存在此记录. 对于复合索引,如果每个列都为空,索引中同样不存在此记录. 如果至少有一个列不为空,则记录存在于索引中.
 
总是使用索引的第一个列
如果索引是建立在多个列上, 只有在它的第一个列(leading column)被where子句引用时,优化器才会选择使用该索引.
SQL> create table multiindexusage ( inda number , indb number , descr varchar2(10));
Table created.
SQL> create index multindex on multiindexusage(inda,indb);
Index created.
SQL> set autotrace traceonly
SQL> select * from multiindexusage where inda = 1;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'MULTIINDEXUSAGE'
2 1 INDEX (RANGE SCAN) OF 'MULTINDEX' (NON-UNIQUE)
SQL> select * from multiindexusage where indb = 1;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (FULL) OF 'MULTIINDEXUSAGE'
很明显, 当仅引用索引的第二个列时,优化器使用了全表扫描而忽略了索引
 
UNION-ALL 替换UNION ( 如果有可能的话)
当SQL语句需要UNION两个查询结果集合时,这两个结果集合会以UNION-ALL的方式被合并, 然后在输出最终结果前进行排序.
如果用UNION ALL替代UNION, 这样排序就不是必要了. 效率就会因此得到提高.
 
WHERE替代ORDER BY
ORDER BY 子句只在两种严格的条件下使用索引.
ORDER BY中所有的列必须包含在相同的索引中并保持在索引中的排列顺序.
ORDER BY中所有的列必须定义为非空.
 
需要当心的WHERE子句
某些SELECT 语句中的WHERE子句不使用索引. 这里有一些例子. 在下面的例子里, ‘!=' 将不使用索引. 记住, 索引只能告诉你什么存在于表中, 而不能告诉你什么不存在于表中.
 
 
 
CBO下使用更具选择性的索引
可选择性(selectivity)
比较一下列中唯一键的数量和表中的行数,就可以判断该列的可选择性。如果该列的”唯一键的数量/表中的行数”的比值越接近1,则该列的可选择性越高,该列就越适合创建索引,同样索引的可选择性也越高。在可选择性高的列上进行查询时,返回的数据就较少,比较适合使用索引查询。
基于成本的优化器(CBO, Cost-Based Optimizer)对索引的选择性进行判断来决定索引的使用是否能提高效率. 如果索引有很高的选择性, 那就是说对于每个不重复的索引键值,只对应数量很少的记录. 比如, 表中共有100条记录而其中有80个不重复的索引键值. 这个索引的选择性就是80/100 = 0.8 . 选择性越高, 通过索引键值检索出的记录就越少. 如果索引的选择性很低, 检索数据就需要大量的索引范围查询操作和ROWID 访问表的操作. 也许会比全表扫描的效率更低.
 
a. 如果检索数据量超过30%的表中记录数.使用索引将没有显著的效率提高.
b. 在特定情况下, 使用索引也许会比全表扫描慢, 但这是同一个数量级上的区别. 而通常情况下,使用索引比全表扫描要块几倍乃至几千倍!
 
避免使用耗费资源的操作
带有DISTINCT,UNION,MINUS,INTERSECT,ORDER BY的SQL语句会启动SQL引擎执行耗费资源的排序(SORT)功能. DISTINCT需要一次排序操作, 而其他的至少需要执行两次排序.
例如,一个UNION查询,其中每个查询都带有GROUP BY子句, GROUP BY会触发嵌入排序(NESTED SORT) ; 这样, 每个查询需要执行一次排序, 然后在执行UNION时, 又一个唯一排序(SORT UNIQUE)操作被执行而且它只能在前面的嵌入排序结束后才能开始执行. 嵌入的排序的深度会大大影响查询的效率.
通常, 带有UNION, MINUS , INTERSECT的SQL语句都可以用其他方式重写.
 
优化GROUP BY
提高GROUP BY 语句的效率, 可以通过将不需要的记录在GROUP BY 之前过滤掉.(用WHERE来替代HAVING )
 
一、 索引(INDEX)使用的问题
1. 索引(INDEX),用还是不用?这是个的问题。
是全表扫描还是索引范围扫描主要考虑SQL的查询速度问题。这里主要关心读取的记录的数目。根据DONALD K .BURLESON的说法,使用索引范围扫描的原则是:
对于数据有原始排序的表,读取少于表记录数40%的查询应该使用索引范围扫描。对读取多于表记录数40%的查询应全表扫描。
对于未排序的表,读取少于表记录数7%的查询应该使用索引范围扫描,反之,对读取多于表记录数7%的查询应全表扫描。
注:在不同的书中,对是否使用索引的读取记录的百分比值不太一致,基本上是一个经验值,但是读取记录的百分比越低,使用索引越有效。
2. 如果列上有建索引,什么SQL查询是有用索引(INDEX)的?什么SQL查询是没有用索引(INDEX)的?
 
存在下面情况的SQL,不会用到索引:
存在数据类型隐形转换的,如:
select * from staff_member where staff_id=’123’
列上有数学运算的,如:
select * from staff_member where salary*2<10000;
使用不等于(<> )运算的,如: select * from staff_member where dept_no<>2001;
使用substr字符串函数的,如: select * from staff_member where substr(last_name,1,4)=’FRED’;
‘%’通配符在第一个字符的,如:
select * from staff_member where first_name like ‘%DON’;
字符串连接(||)的,如: select * from staff_member where first_name||’’=’DONALD’
3. 函数的索引
日期类型也是很容易用到的,而且在SQL语句中会使用to_char函数以查询具体的的范围日期。如:select * from staff_member where TO_CHAR(birth_day,’YYYY’)=’2003’; 我们可以建立基于函数的索引如:CREATE INDEX Ind_emp_birth ON staff_member (to_char((birth_day,’YYYY’));
 
索引使用注意事项:
1)、select,update,delete 语句中的子查询应当有规律地查找少于20%的表行.如果一个语句查找的行数超过总行数的20%,它将不能通过使用索引获得性能上的提高.
2)、索引可能产生碎片,因为记录从表中删除时,相应也从表的索引中删除.表释放的空间可以再用,而索引释放的空间却不能再用.频繁进行删除操作的被索引的表,应当阶段性地重建索引,以避免在索引中造成空间碎片,影响性能.在许可的条件下,也可以阶段性地truncate表,truncate命令删除表中所有记录,也删除索引碎片.
3)、在使用索引时一定要按索引对应字段的顺序进行引用。
 
 
 
阻止 Oracle 使用索引。以下是一些基本规则: 
1, 如果 f1  f2 是同一个表的两个字段,则 f1>f2, f1>=f2
2,  f1 is null, f1 is not null, f1 not in, f1 !=, f1 like ‘%pattern%’; 
3,  Not exist 
 
 
 
 
5.      WHERE子句中的连接顺序 
ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾
6.      SELECT子句中避免使用 ‘ * ‘ 
  1. 使用DECODE函数来减少处理时间 
使用DECODE函数可以避免重复扫描相同记录或重复连接相同的表。 
8.      整合简单,无关联的数据库访问 
如果你有几个简单的数据库查询语句,你可以把它们整合到一个查询中(即使它们之间没有关系例如
SELECT NAME FROM EMP  WHERE EMP_NO = 1234; 
SELECT NAME FROM DPT  WHERE DPT_NO = 10  ;
SELECT NAME FROM CAT  WHERE CAT_TYPE = ‘RD';
上面的3个查询可以被合并成一个
SELECT E.NAME , D.NAME , C.NAME FROM CAT C , DPT D , EMP E,DUAL X 
WHERE NVL(‘X',X.DUMMY) = NVL(‘X',E.ROWID(+)) 
AND NVL(‘X',X.DUMMY) = NVL(‘X',D.ROWID(+)) 
AND NVL(‘X',X.DUMMY) = NVL(‘X',C.ROWID(+)) 
AND E.EMP_NO(+) = 1234 AND D.DEPT_NO(+) = 10 AND C.CAT_TYPE(+) = ‘RD';
 
 
9.      删除重复记录 
最高效的删除重复记录方法 ( 因为使用了ROWID) 
DELETE FROM EMP E  WHERE E.ROWID >(SELECT MIN(X.ROWID)  FROM EMP X 
WHERE X.EMP_NO = E.EMP_NO);
 
10. TRUNCATE替代DELETE 
当删除表中的记录时,在通常情况下回滚段(rollback segments ) 用来存放可以被恢复的信息如果你没有COMMIT事务,ORACLE会将数据恢复到删除之前的状态(准确地说是恢复到执行删除命令之前的状况,而当运用TRUNCATE回滚段不再存放任何可被恢复的信息.当命令运行后,数据不能被恢复.因此很少的资源被调用,执行时间也会很短。(注: TRUNCATE只在删除全表适用,TRUNCATEDDL不是DML) 
 
11. 尽量多使用COMMIT 
只要有可能,在程序中尽量多使用COMMIT, 这样程序的性能得到提高,需求也会因为COMMIT所释放的资源而减少,COMMIT所释放的资源
a. 回滚段上用于恢复数据的信息。 
b. 被程序语句获得的锁。 
c. redo log buffer 中的空间。 
d. Oracle为管理上述3种资源中的内部花费。 
 
 SQL语句优化的心得
Where子句替换HAVING子句
避免使用HAVING子句, HAVING 只会在检索出所有记录之后才对结果集进行过滤. 这个处理需要排序,总计等操作. 如果能通过WHERE子句限制记录的数目,那就能减少这方面的开销.
 
减少对表的查询
在含有子查询的SQL语句中,要特别注意减少对表的查询. 例如:
 低效
SELECT TAB_NAME FROM TABLES WHERE TAB_NAME =
(
 SELECT TAB_NAME  FROM TAB_COLUMNS  WHERE VERSION = 604
)
AND
 DB_VER=
(
 SELECT DB_VER  FROM TAB_COLUMNS  WHERE VERSION = 604
)
高效  
SELECT TAB_NAME FROM TABLES
WHERE (TAB_NAME,DB_VER) =
(
SELECT TAB_NAME,DB_VER) FROM TAB_COLUMNS
WHERE VERSION = 604
)
 
低效:
UPDATE EMP SET EMP_CAT =
(
SELECT MAX(CATEGORY) FROM EMP_CATEGORIES
),
SAL_RANGE = (
SELECT MAX(SAL_RANGE) FROM EMP_CATEGORIES
)
WHERE EMP_DEPT = 0020;
 
高效:
UPDATE EMP  SET (EMP_CAT, SAL_RANGE) =
(
SELECT MAX(CATEGORY) , MAX(SAL_RANGE)  FROM EMP_CATEGORIES 
) WHERE EMP_DEPT = 0020;
 
 
通过内部函数提高SQL效率.
 
 
使用表的别名(Alias)
当在SQL语句中连接多个表时, 请使用表的别名并把别名前缀于每个Column上.这样一来,就可以减少解析的时间并减少那些由Column歧义引起的语法错误.
 
 
EXISTS替代IN
在许多基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接.在这种情况下, 使用EXISTS(或NOT EXISTS)通常将提高查询的效率.
低效:
SELECT *  FROM EMP (基础表)  WHERE EMPNO > 0
AND DEPTNO IN
(
SELECT DEPTNO  FROM DEPT  WHERE LOC = ‘MELB'
)
 
高效:
SELECT * FROM EMP (基础表)  WHERE EMPNO > 0  
AND EXISTS
(
SELECT ‘X'  FROM DEPT  WHERE DEPT.DEPTNO = EMP.DEPTNO
AND LOC = ‘MELB'
)
 
NOT EXISTS替代NOT IN
在子查询中,NOT IN子句将执行一个内部的排序和合并. 无论在哪种情况下,NOT IN都是最低效的 (因为它对子查询中的表执行了一个全表遍历). 为了避免使用NOT IN ,我们可以把它改写成外连接(Outer Joins)或NOT EXISTS.
例如:  
SELECT …  FROM EMP  WHERE DEPT_NO NOT IN
(
SELECT DEPT_NO  FROM DEPT  WHERE DEPT_CAT='A'
);
为了提高效率.改写为:
(方法一: 高效)
SELECT ….  FROM EMP A,DEPT B  WHERE A.DEPT_NO = B.DEPT(+)  
AND B.DEPT_NO IS NULL  AND B.DEPT_CAT(+) = ‘A'  
(方法二: 最高效)
SELECT …. FROM EMP E  WHERE NOT EXISTS
(
SELECT ‘X'  FROM DEPT D WHERE D.DEPT_NO = E.DEPT_NO  
AND DEPT_CAT = ‘A'
);
 
用表连接替换EXISTS
通常来说 , 采用表连接的方式比EXISTS更有效率
SELECT ENAME FROM EMP E  WHERE EXISTS
(
SELECT ‘X'  FROM DEPT  WHERE DEPT_NO = E.DEPT_NO
AND DEPT_CAT = ‘A'
);
 
 
(更高效)
SELECT ENAME FROM DEPT D,EMP E
WHERE E.DEPT_NO = D.DEPT_NO AND DEPT_CAT = ‘A' ;
 
 
EXISTS替换DISTINCT
当提交一个包含一对多表信息(比如部门表和雇员表)的查询时,避免在SELECT子句中使用DISTINCT. 一般可以考虑用EXIST替换
例如:
低效:
SELECT DISTINCT DEPT_NO,DEPT_NAME  FROM DEPT D,EMP E
WHERE D.DEPT_NO = E.DEPT_NO
 
高效:
SELECT DEPT_NO,DEPT_NAME FROM DEPT D  
WHERE EXISTS
(
 SELECT ‘X' FROM EMP E  WHERE E.DEPT_NO = D.DEPT_NO
);
 EXISTS 使查询更为迅速,因为RDBMS核心模块将在子查询的条件一旦满足后,立刻返回结果.
 
EXPLAIN PLAN 分析SQL语句
EXPLAIN PLAN 是一个很好的分析SQL语句的工具,它甚至可以在不执行SQL的情况下分析语句. 通过分析,我们就可以知道ORACLE是怎么样连接表,使用什么方式扫描表(索引扫描或全表扫描)以及使用到的索引名称. 你需要按照从里到外,从上到下的次序解读分析的结果. EXPLAIN PLAN分析的结果是用缩进的格式排列的, 最内部的操作将被最先解读, 如果两个操作处于同一层中,带有最小操作号的将被首先执行.
NESTED LOOP是少数不按照上述规则处理的操作, 正确的执行路径是检查对NESTED LOOP提供数据的操作,其中操作号最小的将被最先处理.
举例:
SQL> list
1 SELECT *
2 FROM dept, emp
3* WHERE emp.deptno = dept.deptno
SQL> set autotrace traceonly /*traceonly 可以不显示执行结果*/
SQL> /
14 rows selected.
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 NESTED LOOPS
2 1 TABLE ACCESS (FULL) OF 'EMP'
3 1 TABLE ACCESS (BY INDEX ROWID) OF 'DEPT'
4 3 INDEX (UNIQUE SCAN) OF 'PK_DEPT' (UNIQUE)
Statistics
----------------------------------------------------------
0 recursive calls
2 db block gets
30 consistent gets
0 physical reads
0 redo size
2598 bytes sent via SQL*Net to client
503 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
14 rows processed
通过以上分析,可以得出实际的执行步骤是:
1. TABLE ACCESS (FULL) OF 'EMP'
2. INDEX (UNIQUE SCAN) OF 'PK_DEPT' (UNIQUE)
3. TABLE ACCESS (BY INDEX ROWID) OF 'DEPT'
4. NESTED LOOPS (JOINING 1 AND 3)
 
 
SQL语句编写注意问题
下面就某些SQL语句的where子句编写中需要注意的问题作详细介绍。在这些where子句中,即使某些列存在索引,但是由于编写了劣质的SQL,系统在运行该SQL语句时也不能使用该索引,而同样使用全表扫描,这就造成了响应速度的极大降低。
1. IS NULL 与 IS NOT NULL
不能用null作索引,任何包含null值的列都将不会被包含在索引中。即使索引有多列这样的情况下,只要这些列中有一列含有null,该列就会从索引中排除。也就是说如果某列存在空值,即使对该列建索引也不会提高性能。
任何在where子句中使用is null或is not null的语句优化器是不允许使用索引的。
2. 联接列
对于有联接的列,即使最后的联接值为一个静态值,优化器是不会使用索引的。下面是一个采用联接查询的SQL语句,
select * from employss where first_name||''||last_name ='Beill Cliton';
如何改写?
3. 带通配符(%)的like语句
同样以上面的例子来看这种情况。目前的需求是这样的,要求在职工表中查询名字中包含cliton的人。可以采用如下的查询SQL语句:
select * from employee where last_name like '%cliton%';
这里由于通配符(%)在搜寻词首出现,所以Oracle系统不使用last_name的索引。在很多情况下可能无法避免这种情况,但是一定要心中有底,通配符如此使用会降低查询速度。然而当通配符出现在字符串其他位置时,优化器就能利用索引。在下面的查询中索引得到了使用:
select * from employee where last_name like 'c%';
4. Order by语句
ORDER BY语句决定了Oracle如何将返回的查询结果排序。Order by语句对要排序的列没有什么特别的限制,也可以将函数加入列中(象联接或者附加等)。任何在Order by语句的非索引项或者有计算表达式都将降低查询速度。
仔细检查order by语句以找出非索引项或者表达式,它们会降低性能。解决这个问题的办法就是重写order by语句以使用索引,也可以为所使用的列建立另外一个索引,同时应绝对避免在order by子句中使用表达式。
5. NOT
我们在查询时经常在where子句使用一些逻辑表达式,如大于、小于、等于以及不等于等等,也可以使用and(与)、or(或)以及not(非)。NOT可用来对任何逻辑运算符号取反。下面是一个NOT子句的例子:
... where not (status ='VALID')
如果要使用NOT,则应在取反的短语前面加上括号,并在短语前面加上NOT运算符。NOT运算符包含在另外一个逻辑运算符中,这就是不等于(<>)运算符。换句话说,即使不在查询where子句中显式地加入NOT词,NOT仍在运算符中,见下例:
... where status <>'INVALID';
再看下面这个例子:
select * from employee where salary<>3000;
对这个查询,可以改写为不使用NOT:
select * from employee where salary<3000 or salary>3000;
以上改写还能更优化,用UNION来完成
虽然这两种查询的结果一样,但是第二种查询方案会比第一种查询方案更快些。第二种查询允许Oracle对salary列使用索引,而第一种查询则不能使用索引。
6. IN和EXISTS
有时候会将一列和一系列值相比较。最简单的办法就是在where子句中使用子查询。在where子句中可以使用两种格式的子查询。
第一种格式是使用IN操作符:
... where column in(select * from ... where ...);
第二种格式是使用EXIST操作符:
... where exists (select 'X' from ...where ...);
我相信绝大多数人会使用第一种格式,因为它比较容易编写,而实际上第二种格式要远比第一种格式的效率高。在Oracle中可以几乎将所有的IN操作符子查询改写为使用EXISTS的子查询。
第二种格式中,子查询以‘select 'X'开始。运用EXISTS子句不管子查询从表中抽取什么数据它只查看where子句。这样优化器就不必遍历整个表而仅根据索引就可完成工作(这里假定在where语句中使用的列存在索引)。相对于IN子句来说,EXISTS使用相连子查询,构造起来要比IN子查询困难一些。
通过使用EXIST,Oracle系统会首先检查主查询,然后运行子查询直到它找到第一个匹配项,这就节省了时间。Oracle系统在执行IN子查询时,首先执行子查询,并将获得的结果列表存放在在一个加了索引的临时表中。在执行子查询之前,系统先将主查询挂起,待子查询执行完毕,存放在临时表中以后再执行主查询。这也就是使用EXISTS比使用IN通常查询速度快的原因。
同时应尽可能使用NOT EXISTS来代替NOT IN,尽管二者都使用了NOT(不能使用索引而降低速度),NOT EXISTS要比NOT IN查询效率更高。
SQL语句排序优化
1.    排序发生的情况:
SQL中包含group by 子句
SQL 中包含order by 子句
SQL 中包含 distinct 子句
SQL 中包含 minus 或 union操作
创建索引时
SQL子查询的调整
1、 理解关联子查询和非关联子查询。
下面是一个非关联子查询:
select staff_name from staff_member where staff_id
in (select staff_id from staff_func);
而下面是一个关联子查询:
select staff_name from staff_member where staff_id in
(
select staff_id from staff_func where staff_member.staff_id=staff_func.staff_id
);
以上返回的结果集是相同的,可是它们的执行开销是不同的:
非关联查询的开销——非关联查询时子查询只会执行一次,而且结果是排序好的,并保存在一个ORACLE的临时段中,其中的每一个记录在返回时都会被父查询所引用。在子查询返回大量的记录的情况下,将这些结果集排序,以及将临时数据段进行排序会增加大量的系统开销。
关联查询的开销——对返回到父查询的的记录来说,子查询会每行执行一次。因此,我们必须保证任何可能的时候子查询用到索引。
2、EXISTS子句和IN子句
带IN的关联子查询是多余的,因为IN子句和子查询中相关的操作的功能是一样的。如: select staff_name from staff_member where staff_id in (select staff_id from staff_func where staff_member.staff_id=staff_func.staff_id);
为非关联子查询指定EXISTS子句是不适当的,因为这样会产生笛卡乘积。如:
select staff_name from staff_member where staff_id Exists (select staff_id from staff_func);
尽量不要使用NOT IN子句。使用MINUS 子句都比NOT IN 子句快,虽然使用MINUS子句要进行两次查询:
select staff_name from staff_member where staff_id in (select staff_id from staff_member MINUS select staff_id from staff_func where func_id like ‘81%’);
3、 任何可能的时候,用标准连接或内嵌视图改写子查询。
基于成本优化器(CBO):
(1)ORACLE 8i 以上版本更多地使用成本优化器,因为它更加智能;
(2)通过optimizer_mode=all_rows 或 first_rows来选择CBO;通过alter session set optimizer_goal=all_rows 或 first_rows来选择CBO;通过添加hint来选择CBO;
(3)使用基于成本优化的一个关键是:存在表和索引的统计资料。通过analyze table 获得表的统计资料;通过analyze index获得索引的统计资料。
(4)对于超过5个表的连接的查询,建议不要使用成本优化器,而是在SQL语句中通过添加/* + rule */提示或者通过指定的执行计划来避免可能会在20分钟以上的SQL解析时间。
 
 
   A.使用可声明的约束而不是通过代码限制
B、代码共享
共享的语句必须满足三个条件
A.      字符级的比较当前被执行的语句和共享池中的语句必须完全相同。
B.      两个语句所指的对象必须完全相同: (同一用户下的对象)
C.      两个SQL语句中必须使用相同的名字的绑定变量(bind variables) 
 
 

 

    C、使用绑定变量而不是文字来优化共享sql
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics