执行计划相关
--执行计划。
--首先 怎么看执行计划
1.追踪trace文件 这个原来写过 有兴趣的可以去:http://www.ucjmh.com/?p=156]http://www.ucjmh.com/?p=156 这里看
2.使用pl/SQL develper等其它ide工具 (这里拿pl/SQL develper说 可以在一行sql上按f5 也可以在File->New->Explain Plan Window)
3.用explain PLAN FOR SQL 然后再select * from table(DBMS_XPLAN.DISPLAY)/*这里的table是关键字 不是表名 注意 不要理解错了*/
4.最简单的, 也是我最喜欢的 set autot[race] ON ,同时执行sql 同时显示执行计划 set autot[race] traceonly 只显示执行计划
5.10046事件
/*
--当前session
alter session set events '10046 trace name context forever, level 8';
alter session set events '10046 trace name context off';
别的session 可以在v$session中找对应session
exec dbms_system.set_ev(127,31923,10046,8,'A');
*/
当然也有可能还有别的。 不过只要能得到执行计划就好了。这只是第一步
接下来要了解: 执行计划是为什么这么生成的
一条sql会在不同的时候有不同的执行计划吗?
怎么解读执行计划,怎么改变执行计划
有必然很造的执行计划吗?
---------------------------------------------------------
当然 在想了解这些东西之前 我们要先了解一些概念
首先要懂 什么是基于规则的优化方式(Rule-Based Optimization,简称为RBO)
什么是基于代价的优化方式(Cost-Based Optimization,简称为CBO)
RBO
优化器在分析SQL语句时,所遵循的是Oracle内部预定的一些规则,对数据是不敏感的。它只借助少量的信息来决定一个sql语句的执行计划,包括:
1)sql语句本身
2)sql中涉及到的table、view、index等的基本信息
3)本地数据库中数据字典中的信息(远程数据库数据字典信息对RBO是无效的)
例如:我们常见的,当一个where子句中的一列有索引时去走索引。但是需要注意,走索引不一定就是优的,比如一个表只有两行数据,一次IO就可以完成全表的检索,而此时走索引时则需要两次IO,这时全表扫描(full table scan)的效率更优。
CBO
它是看语句的代价(Cost),通过代价引擎来估计每个执行计划所需的代价,该代价将每个执行计划所耗费的资源进行量化,CBO根据这个代价选择出最优的执行计划。一个查询所耗费的资源可分为三部分:I/O代价、CPU代价、NETWORK代价。I/O是指把数据从磁盘读入内存时所需代价(该代价是查询所需最主要的,
所以在优化时一个基本原则就是降低I/O总次数);
CPU代价是指处理内存中数据所需的代价,数据一旦读入内存,当我们识别出我们所要的数据后,会在这些数据上执行排序(sort)或连接(join)操作,这需要消耗CPU资源;对于访问远程节点来说,network代价的花费也是很大的。
优化器在判断是否用这种方式时,主要参照的是表及索引的统计信息。统计信息给出表的大小、有多少行、每行的长度等信息。这些统计信息起初在库内是没有的,是做analyze后才出现的,很多的时侯过期统计信息会令优化器做出一个错误的执行计划,因些应及时更新这些信息(dbms_stat.analyze)。
如星型连接排列查询,哈希连接查询,函数索引,和并行查询等一些技术都是基于CBD的。
所以说 优化sql可以说的就是最小化物理I/O
然后优化模式
优化模式包括Rule、Choose、First rows、All rows四种方式
Rule:基于规则的方式。
Choolse:默认的情况下Oracle用的便是这种方式。指的是当一个表或或索引有统计信息,则走CBO的方式,如果表或索引没统计信息,表又不是特别的小,而且相应的列有索引时,那么就走索引,走RBO的方式。
First Rows:它与Choose方式是类似的,所不同的是当一个表有统计信息时,它将是以最快的方式返回查询的最先的几行,从总体上减少了响应时间。
All Rows:也就是我们所说的Cost的方式,当一个表有统计信息时,它将以最快的方式返回表的所有的行,从总体上提高查询的吞吐量。没有统计信息则走RBO的方式。
ROWID 这个应该不是一个陌生的东西 是伪列。 存储的是这条记录的一个物理地址。
Recursive SQL: 有时为了执行用户发出的一个sql语句,Oracle必须执行一些额外的语句,我们将这些额外的语句称之为'recursive calls'或'recursive SQL statements' 比如说一个Update或者一个delete之后 还有一些我们看不到sql去改变了统计信息或者一些数据字典信息
Row Source(行源): 一个查询的结果 或者几张表的连接结果 或者一张表这都是一个行源
Predicate(谓词):一个查询中的WHERE限制条件
selectivity(选择度): 值不值得走索引的一个判断点
我们这里用最简单的 SET autot on的方式来获取
SQL> set autot traceonly
SQL>--我们来看一个最简单的执行计划
SQL> select * from dual;
执行计划
----------------------------------------------------------
Plan hash value: 272002086
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |<--这里是一些操作和消费代价
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 2 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS FULL| DUAL | 1 | 2 | 2 (0)| 00:00:01 | --fts Full Table Scans
--------------------------------------------------------------------------
--这是一个典型的fts
--为实现全表扫描,Oracle读取表中所有的行,并检查每一行是否满足语句的WHERE限制条件一个多块读操作可以使一次I/O能读取多块数据块(db_block_multiblock_read_count参数设定),
--而不是只读取一个数据块,这极大的减 少了I/O总次数,提高了系统的吞吐量,所以利用多块读的方法可以十分高效地实现全表扫描,
--而且只有在全表扫描的情况下才能使用多块读操作。在这种访问模 式下,每个数据块只被读一次。
-- 使用FTS的前提条件:在较大的表上不建议使用全表扫描,除非取出数据的比较多,超过总量的5% —— 10%,或你想使用并行查询功能时。
-------------------------------------------------------------------------------
SELECT * FROM corp_info WHERE ROWID='AAAZNWAAGAAAAMnAAG'
SELECT STATEMENT, GOAL = ALL_ROWS 1 479 1
TABLE ACCESS BY USER ROWID FRK CORP_INFO 1 479 1
--行的ROWID指出了该行所在的数据文件、数据块以及行在该块中的位置,所以通过ROWID来存取数据可以快速定位到目标数据上,
--是Oracle存取单行数据的最快方法。
--这种存取方法不会用到多块读操作,一次I/O只能读取一个数据块。我们会经常在执行计划中看到该存取方法,如通过索引查询数据。
--------------------------------------------------------------------------------------------------
SELECT * FROM CORP_INFO WHERE CORP_INFO_ID<'1151017416'
SELECT STATEMENT, GOAL = ALL_ROWS 1 479 4
TABLE ACCESS BY INDEX ROWID FRK CORP_INFO 1 479 4
INDEX RANGE SCAN FRK PK_INFO_ID 1 3
这是一个基于index的 RANGE SCAN
使用index rang scan的3种情况:
(a) 在唯一索引列上使用了range操作符(> < <> >= <= between)
(b) 在组合索引上,只使用部分列进行查询,导致查询出多行
(c) 对非唯一索引列上进行的任何查询。
--索引扫描(Index Scan或index lookup)
/* 我们先通过index查找到数据对应的rowid值(对于非唯一索引可能返回多个rowid值),
然后根据rowid直接从表中得到具体的数据,这 种查找方式称为索引扫描或索引查找(index lookup)。
一个rowid唯一的表示一行数据,该行对应的数据块是通过一次i/o得到的,在此情况下该次i/o只会读取一个数据库块。
在索引中,除了存储每个索引的值外,索引还存储具有此值的行对应的ROWID值。
索引扫描可以由2步组成:
(1) 扫描索引得到对应的rowid值。
(2) 通过找到的rowid从表中读出具体的数据。
每步都是单独的一次I/O,但是对于索引,由于经常使用,绝大多数都已经CACHE到内存中,
所以第1步的 I/O经常是逻辑I/O,即数据可以从内存中得到。但是对于第2步来说,
如果表比较大,则其数据不可能全在内存中,所以其I/O很有可能是物理I/O,
这是一个机械操作,相对逻辑I/O来说,是极其费时间的。
所以如果多大表进行索引扫描,取出的数据如果大于总量的5% —— 10%,使用索引扫描会效率下降很多。*/
--使之走索引是要在一定的选择度下,如果选择度不够 oracle会认为他不值得走索引 当然当选择库达到时 如果你的数据类型不匹配或者又嵌套了函数 也是不会走的
--根据索引的类型与where限制条件的不同,有4种类型的索引扫描:
索引唯一扫描(index unique scan)--通过唯一索引查找一个数值经常返回单个ROWID.如果存在UNIQUE 或PRIMARY KEY 约束(它保证了语句只存取单行)的话,Oracle经常实现唯一性扫描。
索引范围扫描(index range scan)--使用一个索引存取多行数据,在唯一索引上使用索引范围扫描的典型情况下是在谓词(where限制条件)中使用了范围操作符(如>、<、<>、>=、<=、between)
索引全扫描(index full scan) --与全表扫描对应,也有相应的全索引扫描。而且此时查询出的数据都必须从索引中可以直接得到。
--使用单块读方式有序读取索引块,产生db file sequential reads事件,当采用该方式读取大量索引全扫描,效率低下
索引快速扫描(index fast full scan)--扫描索引中的所有的数据块,与 index full scan很类似,
--但是一个显著的区别就是它不对查询出的数据进行排序,即数据不是以排序顺序被返回。
--在这种存取方法中,可以使用多块读功能,也可以使用并行读入,以便获得最大吞吐量与缩短执行时间
--通过牺牲内存与临时表空间换取性能,因此在内存不足或饱和状态应进行合理权衡
--使用多块读的方式读取索引块,产生db file scattered reads 事件,读取时高效,但为无序读取
---------------------------------------------------------------------------------------
--INDEX FULL SCAN 和 INDEX FAST FULL SCAN 的相同点和差异点
-- /*+ index_ffs(tablenaem indexname) */ /* full(tablename) */ hint的写法
上面已经说了 INDEX FAST FULL SCAN 不会对查询出的数据进行排序返回,除了这一点 还有:
INDEX FAST FULL SCAN 类似于full table scan,使用该方式当在高速缓存中没有找到所需的索引块时,
则根据db_file_multiblock_read_count的值进行多块读操 作。对于索引的分支结构只是简单的获取,然后扫描所有的叶结点
。其结果是导致索引结构没有访问,获取的数据没有根据索引键的顺序排序
INDEX FAST FULL SCAN使用multiblock_read,故产生db file scattered reads 事件
INDEX FULL SCAN 与INDEX FAST FULL SCAN所不同的是,INDEX FULL SCAN会完全按照索引存储的顺序依次访问整个索引树。
当访问到叶结点之后,按照双向链表方式读取相连节点的值。换言之,对于索引上所有的数据是按照有序的方式来读取的。
如果索引块没有在高速缓存中被找到时,则需要从数 据文件中单块进行读取。对于需要读取大量数据的全索引扫描而言,将使其变得低效。
INDEX FULL SCAN使用single read,故产生db file sequential reads事件
前提count(*)操作几乎总是选择index fast full scan,而索引列上的order by子句几乎总是选择index full scan
他们的共同点是:当select和where中出现的列都存在索引是发生index full scan与index fast full scan的前提
查询返回的数据行总数占据整个索引10%以上的比率
----------------------------------------------------------------------
--表之间的连接
查询中表与表的连接太平常了。在写法上 LEFT JOIN RIGHT JOIN INNER JOIN 或者逗号分隔
--Join是一种试图将两个表结合在一起的谓词,一次只能连接2个表,表连接也可以被称为表关联
--row source(表)之间的连接顺序对于查询的效率有非常大的影响。通过首先存取特定的表,即将该表作为驱动表,
这样可以先应用某些限制条件,从而得到一个 较小的row source,使连接的效率较高,
这也就是我们常说的要先执行限制条件的原因。一般是在将表读入内存时,应用where子句中对该表的限制条件
根据2个row source的连接条件的中操作符的不同,
可以将连接分为等值连接(如WHERE A.COL3 = B.COL4)、
非等值连接(WHERE A.COL3 > B.COL4)、
外连接(WHERE A.COL3 = B.COL4(+))。
连接类型:
目前为止,无论连接操作符如何,典型的连接类型共有3种:
排序 - - 合并连接(Sort Merge Join (SMJ) )
嵌套循环(Nested Loops (NL) )
哈希连接(Hash Join)
另外,还有一种Cartesian product(笛卡尔积),一般情况下,尽量避免使用。
-----------------------------
排序 - - 合并连接(Sort Merge Join, SMJ)/*+ ordered */
内部连接过程:
1) 首先生成row source1需要的数据,然后对这些数据按照连接操作关联列(如A.col3)进行排序。
2) 随后生成row source2需要的数据,然后对这些数据按照与sort source1对应的连接操作关联列(如B.col4)进行排序。
3) 最后两边已排序的行被放在一起执行合并操作,即将2个row source按照连接条件连接起来
SQL> select /*+ ordered */ e.deptno, d.deptno
from emp e, dept d
where e.deptno = d.deptno
order by e.deptno, d.deptno;
已选择14行。
执行计划
----------------------------------------------------------
Plan hash value: 150391907
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 14 | 42 | 4 (25)| 00:00:01 |
| 1 | SORT ORDER BY | | 14 | 42 | 4 (25)| 00:00:01 |
|* 2 | TABLE ACCESS FULL| EMP | 14 | 42 | 3 (0)| 00:00:01 |
---------------------------------------------------------------------------
--排序是一个费时、费资源的操作,特别对于大表。基于这个原因,
--SMJ经常不是一个特别有效的连接方法,但是如果2个row source都已经预先排序 也是可以的
----------------
嵌套循环(Nested Loops, NL)
--这个连接的过程就是两层的嵌套循环,所以要遵循的原理一定是次数越少越好
--所以一般来说我们已经把小表做为驱动表,用于和外部表进行循环。但是也不一定这样就是最小化的I/O,所以要根据不同的环境做不同的调整
--如果选择错了驱动表,有的时候执行时间会差几百倍
nl的一个内部连接的过程就是
row source1 row1 --> row source2
row source1 row2 --> row source2
row source1 row3 --> row source2
row source1 row4 --> row source2
............
row source1 rown --> row source2
--NL的特点是:
--如果driving row source(外部表)比较小,并且在inner row source(内部表)上有唯一索引,或有高选择性非唯一索引时,
--使用这种方法可以得到较好的效率。NESTED LOOPS有其它连接方法没有的的一个优点是:可以先返回已经连接的行
--,而不必等待所有的连接操作处理完才返回数据,这可以实现快速的响应时间
SELECT * FROM dept_info d ,corp_info_uc c WHERE d.dept_id=c.corp_info_id
SELECT STATEMENT, GOAL = ALL_ROWS 42 19572 45
NESTED LOOPS
NESTED LOOPS 42 19572 45
TABLE ACCESS FULL FRK DEPT_INFO 42 4200 3
INDEX UNIQUE SCAN FRK PK_INFO_UC_ID 1 0
TABLE ACCESS BY GLOBAL INDEX ROWID FRK CORP_INFO_UC 1 366 1
------------------------------------------------
哈希连接(Hash Join, HJ)--HASH_JOIN_ENABLED=TRUE 这个参数可
--理论上来说比NL与SMJ更高效,而且只用在CBO优化器中。
原理是:
较小的row source被用来构建hash table与bitmap,第2个row source被用来被hansed,并与第一个row source生成的hash table进行匹配,以便进行进一步的连接。
Bitmap被用来作为一种比较快的查找方法,来检查在hash table中是否有匹配的行。
当hash table比较大而不能全部容纳在内存中时,这种查找方法更为有用。
这种连接方法也有NL连接中所谓的驱动表的概念,被构建为hash table与bitmap的表为驱动表,
当被构建的hash table与bitmap能被容纳在内存中时,这种连接方式的效率极高。
-------------
笛卡尔集: MERGE JOIN CARTESIAN
CARTESIAN关键字指出了在2个表之间做笛卡尔乘积。假如表emp有n行,dept表有m行,笛卡尔乘积的结果就是得到n * m行结果
-------------什么时候用什么连接
排序 - - 合并连接(Sort Merge Join, SMJ):
a) 对于非等值连接,这种连接方式的效率是比较高的。
b) 如果在关联的列上都有索引,效果更好。
c) 对于将2个较大的row source做连接,该连接方法比NL连接要好一些。
d) 但是如果sort merge返回的row source过大,则又会导致使用过多的rowid在表中查询数据时,数据库性能下降,因为过多的I/O.
嵌套循环(Nested Loops, NL):
a) 如果driving row source(外部表)比较小,并且在inner row source(内部表)上有唯一索引,或有高选择性非唯一索引时,使用这种方法可以得到较好的效率。
b) NESTED LOOPS有其它连接方法没有的的一个优点是:可以先返回已经连接的行,而不必等待所有的连接操作处理完才返回数据,这可以实现快速的响应时间。
哈希连接(Hash Join, HJ):
a) 这种方法是在oracle7后来引入的,使用了比较先进的连接理论,一般来说,其效率应该好于其它2种连接,但是这种连接只能用在CBO优化器中,而且需要设置合适的hash_area_size参数,才能取得较好的性能。
b) 在2个较大的row source之间连接时会取得相对较好的效率,在一个row source较小时则能取得更好的效率。
c) 只能用于等值连接中
一些强制走某些计划的写法:
1. /*+ALL_ROWS*/表明对语句块选择基于开销的优化方法,并获得最佳吞吐量,使资源消耗最小化.
例如: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’;
3. /*+CHOOSE*/表明如果数据字典中有访问表的统计信息,将基于开销的优化方法,并获得最佳的吞吐量;
表明如果数据字典中没有访问表的统计信息,将基于规则开销的优化方法;
例如:SELECT /*+CHOOSE*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO=’SCOTT’;
4. /*+RULE*/表明对语句块选择基于规则的优化方法.
例如:SELECT /*+ RULE */ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO=’SCOTT’;
5. /*+FULL(TABLE)*/表明对表选择全局扫描的方法.
例如:SELECT /*+FULL(A)*/ EMP_NO,EMP_NAM FROM BSEMPMS A WHERE EMP_NO=’SCOTT’;
6. /*+ROWID(TABLE)*/提示明确表明对指定表根据ROWID进行访问.
例如:SELECT /*+ROWID(BSEMPMS)*/ * FROM BSEMPMS WHERE ROWID>=’AAAAAAAAAAAAAA’AND EMP_NO=’SCOTT’;
7. /*+CLUSTER(TABLE)*/提示明确表明对指定表选择簇扫描的访问方法,它只对簇对象有效.
例如:SELECT /*+CLUSTER */ BSEMPMS.EMP_NO,DPT_NO FROM BSEMPMS,BSDPTMSWHERE DPT_NO=’TEC304′ AND BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;
8. /*+INDEX(TABLE INDEX_NAME)*/表明对表选择索引的扫描方法.
例如:SELECT /*+INDEX(BSEMPMS SEX_INDEX) USE SEX_INDEX BECAUSE THERE ARE FEWMALE BSEMPMS */ FROM BSEMPMS WHERE SEX='M';
9. /*+INDEX_ASC(TABLE INDEX_NAME)*/表明对表选择索引升序的扫描方法.
例如:SELECT /*+INDEX_ASC(BSEMPMS PK_BSEMPMS) */ FROM BSEMPMS WHERE DPT_NO=’SCOTT’;
10. /*+INDEX_COMBINE*/为指定表选择位图访问路经,如果INDEX_COMBINE中没有提供作为参数的索引,将选择出位图索引的布尔组合方式.
例如:SELECT /*+INDEX_COMBINE(BSEMPMS SAL_BMI HIREDATE_BMI)*/ * FROM BSEMPMSWHERE SAL<5000000 AND HIREDATE
11. /*+INDEX_JOIN(TABLE INDEX_NAME)*/提示明确命令优化器使用索引作为访问路径.
例如:SELECT /*+INDEX_JOIN(BSEMPMS SAL_HMI HIREDATE_BMI)*/ SAL,HIREDATEFROM 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';
14. /*+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_NOAND 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依此顺序对其连接.
例如: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)*/将指定表与嵌套的连接的行源进行连接,并把指定表作为内部表.
例如: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)*/将指定的表与其他行源通过合并排序连接方式连接起来.
例如:SELECT /*+USE_MERGE(BSEMPMS,BSDPTMS)*/ * FROM BSEMPMS,BSDPTMS WHERE BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;
24. /*+USE_HASH(TABLE)*/将指定的表与其他行源通过哈希连接方式连接起来.
例如:SELECT /*+USE_HASH(BSEMPMS,BSDPTMS)*/ * FROM BSEMPMS,BSDPTMS WHERE BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;
25. /*+DRIVING_SITE(TABLE)*/强制与ORACLE所选择的位置不同的表进行查询执行.
例如:SELECT /*+DRIVING_SITE(DEPT)*/ * FROM BSEMPMS,DEPT@BSDPTMS WHERE BSEMPMS.DPT_NO=DEPT.DPT_NO;
26. /*+LEADING(TABLE)*/将指定的表作为连接次序中的首表.
27. /*+CACHE(TABLE)*/当进行全表扫描时,CACHE提示能够将表的检索块放置在缓冲区缓存中最近最少列表LRU的最近使用端
例如:SELECT /*+FULL(BSEMPMS) CAHE(BSEMPMS) */ EMP_NAM FROM BSEMPMS;
28. /*+NOCACHE(TABLE)*/当进行全表扫描时,CACHE提示能够将表的检索块放置在缓冲区缓存中最近最少列表LRU的最近使用端
例如:SELECT /*+FULL(BSEMPMS) NOCAHE(BSEMPMS) */ EMP_NAM FROM BSEMPMS;
29. /*+APPEND*/直接插入到表的最后,可以提高速度.
insert /*+append*/ into test1 select * from test4 ;
30. /*+NOAPPEND*/通过在插入语句生存期内停止并行模式来启动常规插入.
insert /*+noappend*/ into test1 select * from test4 ;