zoukankan      html  css  js  c++  java
  • Oracle-Hints详解

    Oracle-Hints详解

    https://www.2cto.com/database/201611/568701.html

    概述

    先了解一下Oracle的优化器:

    RBO: Rule-Based Optimization 基于规则的优化器

    RBO自ORACLE 6以来被采用,一直沿用至ORACLE 9i. ORACLE 10g开始,ORACLE已经彻底丢弃了RBO

    CBO: Cost-Based Optimization 基于代价的优化器。

    CBO优化器根据SQL语句生成一组可能被使用的执行计划,估算出每个执行计划的代价,并调用计划生成器(Plan Generator)生成执行计划,比较执行计划的代价,最终选择选择一个代价最小的执行计划。

    CBO由以下组件构成: 查询转化器(Query Transformer) 、代价评估器(Estimator)、 计划生成器(Plan Generator)

    在Oracle 10g中,CBO 可选的运行模式有2种:

    (1) FIRST_ROWS(n)

    (2) ALL_ROWS – 10g中的默认值

    查看CBO 模式:

    SQL> show parameter optimizer_mode

    NAME TYPE VALUE


    optimizer_mode string ALL_ROWS

    修改CBO 模式的三种方法:

    (1) Sessions级别

    SQL> alter session set optimizer_mode=all_rows;

    (2) 系统级别

    修改pfile 参数:

    OPTIMIZER_MODE=RULE/CHOOSE/FIRST_ROWS/ALL_ROWS

    (3) 语句级别

    用Hint(/* + … */)来设定

    Select /*+ first_rows(10) */ name from table;

    Select /*+ all_rows */ name from table;

    基于代价的优化器(CBO)是很聪明的,在绝大多数情况下它会选择正确的优化器,减轻了DBA的负担。但有时它也聪明反被聪明误,选择了很差的执行计划,使某个语句的执行变得奇慢无比。

    此时就需要DBA进行人为的干预,告诉优化器使用我们指定的存取路径或连接类型生成执行计划,从而使语句高效的运行。例如,如果我们认为对于一个特定的语句,执行全表扫描要比执行索引扫描更有效,则我们就可以指示优化器使用全表扫描。

    在Oracle中,是通过为语句添加 Hints(提示)来实现干预优化器优化的目的。

    Oracle Hints是一种机制,用来告诉优化器按照我们的告诉它的方式生成执行计划。

    我们可以用Oracle Hints来实现:

    1. 使用的优化器的类型 2) 基于代价的优化器的优化目标,是all_rows还是first_rows。 3) 表的访问路径,是全表扫描,还是索引扫描,还是直接利用rowid。 4) 表之间的连接类型 5) 表之间的连接顺序 6) 语句的并行程度

    在使用Hint时需要注意的一点是,并非任何时刻Hint都起作用。 导致HINT 失效的原因有如下2点:

    如果CBO 认为使用Hint 会导致错误的结果时,Hint将被忽略。

    如索引中的记录因为空值而和表的记录不一致时,结果就是错误的,会忽略hint。

    如果表中指定了别名,那么Hint中也必须使用别名,否则Hint也会忽略。

    Select /+full(a)/ * from t a; -- 使用hint

    Select /*+full(t) */ * from t a; --不使用hint

    语法

    {DELETE|INSERT|SELECT|UPDATE} /*+ hint [text] [hint[text]]... */

    or

    {DELETE|INSERT|SELECT|UPDATE} --+ hint [text] [hint[text]]...

    DELETE、INSERT、SELECT和UPDATE是标识一个语句块开始的关键字,包含提示的注释只能出现在这些关键字的后面,否则提示无效。 2) “+”号表示该注释是一个Hints,该加号必须立即跟在”/*”的后面,中间不能有空格。 3) hint是下面介绍的具体提示之一,如果包含多个提示,则每个提示之间需要用一个或多个空格隔开。 4) text 是其它说明hint的注释性文本

    如果你没有正确的指定Hints,Oracle将忽略该Hints,并且不会给出任何错误。

    Hints类型

    另:每个SELECT/INSERT/UPDATE/DELETE命令后只能有一个/+ /,但提示内容可以有多个,可以用逗号分开,空格也可以。

    如:/*+ ordered index() use_nl() */

    在SQL语句优化过程中,我们经常会用到hint,现总结一下在SQL优化过程中常见Oracle HINT的用法:

    1./+ALL_ROWS/

    表明对语句块选择基于开销的优化方法,并获得最佳吞吐量,使资源消耗最小化.

    当CBO 模式设置为ALL_ROWS时,Oracle 会用最快的速度将SQL执行完毕,将结果集全部返回,它和FIRST_ROWS(n)的区别在于,ALL_ROWS强调以最快的速度将SQL执行完毕,并将所有的结果集反馈回来,而FIRST_ROWS(n)则侧重于返回前n条记录的执行时间。

    SELECT /+ALL+_ROWS/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT';

    2./+FIRST_ROWS/

    表明对语句块选择基于开销的优化方法,并获得最佳响应时间,使资源消耗最小化.

    SELECT /+FIRST_ROWS/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT';

    当CBO 的优化模式设置为FIRST_ROWS(n)时,Oracle 在执行SQL时,优先考虑将结果集中的前n条记录以最快的速度反馈回来,而其他的结果并不需要同时返回。

    这种需求在一些网站或者BBS的分页上经常看到,比如每次只显示查询信息的前20条或者BBS上的前20个帖子, 这时候设置FIRST_ROWS(20)就非常合适,优化器并不需要同事将所有符合条件的结果返回,用户也不需要。这时,CBO将考虑用一种最快的返回前20条记录的执行计划,这种执行计划对于SQL的整体执行时间也不不是最快的,但是在返回前20条记录的处理上,确实最快的。

    Select /*+ first_rows(10) */b.x,b.y from

    (

    Select /*+ first_rows(10) / a., rownum rnum from

    (

    Select /*+ first_rows(20) */ * from t order by x

    ) a

    Where rownum < 20

    ) b where rnum >=10;
    分页例子中,每次从结果集中取10条记录,记录按照x字段排序。

    注意: 排序使用的字段x 必须创建有索引,否则CBO 会忽略FIRST_ROWS(n),而使用ALL_ROWS.

    3./+CHOOSE/

    表明如果数据字典中有访问表的统计信息,将基于开销的优化方法,并获得最佳的吞吐量;

    表明如果数据字典中没有访问表的统计信息,将基于规则开销的优化方法;

    SELECT /+CHOOSE/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT';

    1. /+RULE/

    表明对语句块选择基于规则的优化方法.

    例如:

    SELECT /*+ RULE */ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT';

    1. /+FULL(TABLE)/

    表明对表选择全局扫描的方法.

    该Hint告诉优化器对指定的表通过全表扫描的方式访问数据。

    例如:

    SELECT /+FULL(A)/ EMP_NO,EMP_NAM FROM BSEMPMS A WHERE EMP_NO='SCOTT';

    要注意,如果表有别名,在hint里也要用别名

    1. /+ROWID(TABLE)/

    提示明确表明对指定表根据ROWID进行访问.

    例如:

    SELECT /+ROWID(BSEMPMS)/ * FROM BSEMPMS WHERE ROWID>='AAAAAAAAAAAAAA'

    AND EMP_NO='SCOTT';

    1. /+CLUSTER(TABLE)/

    提示明确表明对指定表选择簇扫描的访问方法,它只对簇对象有效.

    例如:

    SELECT /*+CLUSTER */ BSEMPMS.EMP_NO,DPT_NO FROM BSEMPMS,BSDPTMS

    WHERE DPT_NO='TEC304' AND BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;

    1. /+INDEX(TABLE INDEX_NAME)/

    表明对表选择索引的扫描方法.

    Index hint 告诉优化器对指定的表通过索引的方式访问数据,当访问索引会导致结果集不完整时,优化器会忽略这个Hint。

    例如:

    SELECT /*+INDEX(BSEMPMS SEX_INDEX) USE SEX_INDEX BECAUSE THERE ARE FEWMALE BSEMPMS */ FROM BSEMPMS WHERE SEX='M';

    谓词里有索引字段,才会用索引。

    1. /+INDEX_ASC(TABLE INDEX_NAME)/

    表明对表选择索引升序的扫描方法.

    例如:

    SELECT /*+INDEX_ASC(BSEMPMS PK_BSEMPMS) */ FROM BSEMPMS WHERE DPT_NO='SCOTT';

    1. /+INDEX_COMBINE/

    为指定表选择位图访问路经,如果INDEX_COMBINE中没有提供作为参数的索引,将选择出位图索引的布尔组合方式.

    例如:

    SELECT /+INDEX_COMBINE(BSEMPMS SAL_BMI HIREDATE_BMI)/ * FROM BSEMPMS

    WHERE SAL<5000000 AND HIREDATE11. /+INDEX_JOIN(TABLE INDEX_NAME)/提示明确命令优化器使用索引作为访问路径.

    例如:SELECT /+INDEX_JOIN(BSEMPMS SAL_HMI HIREDATE_BMI)/ SAL,HIREDATE

    FROM BSEMPMS WHERE SAL<60000;12. /+INDEX_DESC(TABLE INDEX_NAME)/表明对表选择索引降序的扫描方法.例如:SELECT /+INDEX_DESC(BSEMPMS PK_BSEMPMS) / FROM BSEMPMS WHERE DPT_NO='SCOTT';13. /+INDEX_FFS(TABLE INDEX_NAME)/对指定的表执行快速全索引扫描,而不是全表扫描的办法.例如:SELECT /+INDEX_FFS(BSEMPMS IN_EMPNAM)/ * FROM BSEMPMS WHERE DPT_NO='TEC305';

    1. /+ADD_EQUAL TABLE INDEX_NAM1,INDEX_NAM2,.../提示明确进行执行规划的选择,将几个单列索引的扫描合起来.例如:SELECT /+INDEX_FFS(BSEMPMS IN_DPTNO,IN_EMPNO,IN_SEX)/ * FROM BSEMPMS WHERE EMP_NO='SCOTT' AND DPT_NO='TDC306';15. /+USE_CONCAT/对查询中的WHERE后面的OR条件进行转换为UNION ALL的组合查询.例如:SELECT /+USE_CONCAT/ * FROM BSEMPMS WHERE DPT_NO='TDC506' AND SEX='M';16. /+NO_EXPAND/对于WHERE后面的OR 或者IN-LIST的查询语句,NO_EXPAND将阻止其基于优化器对其进行扩展.例如:SELECT /+NO_EXPAND/ * FROM BSEMPMS WHERE DPT_NO='TDC506' AND SEX='M';17. /+NOWRITE/禁止对查询块的查询重写操作.18. /+REWRITE/可以将视图作为参数.19. /+MERGE(TABLE)/能够对视图的各个查询进行相应的合并.例如:SELECT /*+MERGE(V) */ A.EMP_NO,A.EMP_NAM,B.DPT_NO FROM BSEMPMS A (SELET DPT_NO

    ,AVG(SAL) AS AVG_SAL FROM BSEMPMS B GROUP BY DPT_NO) V WHERE A.DPT_NO=V.DPT_NO

    AND A.SAL>V.AVG_SAL;20. /+NO_MERGE(TABLE)/对于有可合并的视图不再合并.例如:SELECT /+NO_MERGE(V) / A.EMP_NO,A.EMP_NAM,B.DPT_NO FROM BSEMPMS A (SELECT DPT_NO,AVG(SAL) AS AVG_SAL FROM BSEMPMS B GROUP BY DPT_NO) V WHERE A.DPT_NO=V.DPT_NO AND A.SAL>V.AVG_SAL;21. /+ORDERED/根据表出现在FROM中的顺序,ORDERED使ORACLE依此顺序对其连接.该hint 告诉Oracle 按照From后面的表的顺序来选择驱动表,Oracle 建议在选择驱动表上使用Leading,它更灵活一些。例如: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;22. /+USE_NL(TABLE)/多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP将指定表与嵌套的连接的行源进行连接,并把指定表作为内部表.在多表关联查询中,指定使用nest loops方式进行多表关联。例如:SELECT /+ORDERED USE_NL(BSEMPMS)/ BSDPTMS.DPT_NO,BSEMPMS.EMP_NO,BSEMPMS.EMP_NAM FROM BSEMPMS,BSDPTMS WHERE BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;23. /+USE_MERGE(TABLE)/多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP将指定的表与其他行源通过合并排序连接方式连接起来.在多表关联查询中,指定使用merge join方式进行多表关联。例如:SELECT /+USE_MERGE(BSEMPMS,BSDPTMS)/ * FROM BSEMPMS,BSDPTMS WHERE BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;24. /+USE_HASH(TABLE)/多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP将指定的表与其他行源通过哈希连接方式连接起来.在多表关联查询中,指定使用hash join方式进行多表关联。例如:SELECT /+USE_HASH(BSEMPMS,BSDPTMS)/ * FROM BSEMPMS,BSDPTMS WHERE BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;

    1. /+DRIVING_SITE(TABLE)/强制与ORACLE所选择的位置不同的表进行查询执行.例如:SELECT /+DRIVING_SITE(DEPT)/ * FROM BSEMPMS,DEPT@BSDPTMS WHERE BSEMPMS.DPT_NO=DEPT.DPT_NO;26. /+LEADING(TABLE)/将指定的表作为连接次序中的首表.在一个多表关联的查询中,该Hint指定由哪个表作为驱动表,告诉优化器首先要访问哪个表上的数据。 select /+leading(t1,t) / * from scott.dept t,scott.emp t1 where t.deptno=t1.deptno;27. /+CACHE(TABLE)/在全表扫描操作中,如果使用这个提示,Oracle 会将扫描的到的数据块放到LRU(least recently Used: 最近很少被使用列表,是Oracle 判断内存中数据块活跃程度的一个算法)列表的最被使用端(数据块最活跃端),这样数据块就可以更长时间地驻留在内存当中。如果有一个经常被访问的小表,这个设置会提高查询的性能;同时CACHE也是表的一个属性,如果设置了表的cache属性,它的作用和hint一样,在一次全表扫描之后,数据块保留在LRU列表的最活跃端。例如:SELECT /+FULL(BSEMPMS) CAHE(BSEMPMS) / EMP_NAM FROM BSEMPMS;28. /+NOCACHE(TABLE)/例如:SELECT /+FULL(BSEMPMS) NOCAHE(BSEMPMS) / EMP_NAM FROM BSEMPMS;29. /+APPEND/直接插入到表的最后,可以提高速度.提示数据库以直接加载的方式(direct load)将数据加载入库。这个hint 用的比较多。 尤其在插入大量的数据,一般都会用此hint。insert /+append/ into test1 select * from test4 ;30. /+NOAPPEND/通过在插入语句生存期内停止并行模式来启动常规插入.insert /+noappend/ into test1 select * from test4 ;31. NO_INDEX: 指定不使用哪些索引/+ NO_INDEX ( table [index [index]…] ) / select /+ no_index(emp ind_emp_sal ind_emp_deptno)/ * from emp where deptno=200 and sal>300;并行执行相关的Hintparallel在sql中指定执行的并行度,这个值将会覆盖自身的并行度select /+ parallel(emp,4)/ * from emp where deptno=200 and sal>300;
      关于表的并行度,我们在创建表的时候可以指定,如:SQL> CREATE TABLE Anqing

    2 (

    3 name VARCHAR2 (10)

    4 )

    5 PARALLEL 2;表已创建。SQL> select degree from all_tables where table_name = 'ANQING'; -- 查看表的并行度

    DEGREE

    2SQL> alter table anqing parallel(degree 3); -- 修改表的并行度

    表已更改。

    SQL> select degree from all_tables where table_name = 'ANQING';

    DEGREE

    SQL> alter table anqing noparallel; -- 取消表的并行度

    表已更改。

    SQL> select degree from all_tables where table_name = 'ANQING';

    DEGREE

    no_parallel在sql中指定执行的不使用并行select /*+ no_parallel(t) / count() from t;

  • 相关阅读:
    LeetCode Array Easy 414. Third Maximum Number
    LeetCode Linked List Medium 2. Add Two Numbers
    LeetCode Array Easy 283. Move Zeroes
    LeetCode Array Easy 268. Missing Number
    LeetCode Array Easy 219. Contains Duplicate II
    LeetCode Array Easy 217. Contains Duplicate
    LeetCode Array Easy 189. Rotate Array
    LeetCode Array Easy169. Majority Element
    LeetCode Array Medium 11. Container With Most Water
    LeetCode Array Easy 167. Two Sum II
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/9455841.html
Copyright © 2011-2022 走看看