《2022年SQL优化根据 .pdf》由会员分享,可在线阅读,更多相关《2022年SQL优化根据 .pdf(17页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、我们将简要地介绍以下的Oracle 主题:- 外部调整 :我们应该记住Oracle 并不是单独运行的。因此我们将查看一下通过调整Oracle 服务器以得到高的性能。-Row re-sequencing 以减少磁盘I/O :我们应该懂得Oracle 调优最重要的目标是减少 I/O 。-Oracle SQL 调整。 Oracle SQL 调整是 Oracle 调整中最重要的领域之一,只要通过一些简单的SQL 调优规则就可以大幅度地提升SQL 语句的性能,这是一点都不奇怪的。- 调整 Oracle 排序:排序对于Oracle 性能也是有很大影响的。- 调整 Oracle 的竞争:表和索引的参数设置对
2、于UPDATE 和 INSERT 的性能有很大的影响。我们首先从调整Oracle 外部的环境开始。如果内存和CPU 的资源不足的话,任何的Oracle 调整都是没有帮助的。外部的性能问题Oracle 并不是单独运行的。Oracle 数据库的性能和外部的环境有很大的关系。这些外部的条件包括有: CPU-CPU 资源的不足令查询变慢。当查询超过了Oracle 服务器的CPU 性能时,你的数据库性能就受到CPU 的限制。内存 - 可用于Oralce 的内存数量也会影响SQL 的性能,特别是在数据缓冲和内存排序方面。网络 - 大量的Net8 通信令 SQL 的性能变慢。许多新手都错误的认为应该首先调整
3、Oracle 数据库,而不是先确认外部资源是否足够。实际上,如果外部环境出现瓶颈,再多的Oracle 调整都是没有帮助的。在检查 Oracle 的外部环境时,有两个方面是需要注意的:1 、当运行队列的数目超过服务器的CPU 数量时,服务器的性能就会受到CPU 的限制。补救的方法是为服务器增加额外的CPU 或者关闭需要很多处理资源的组件,例如Oracle Parallel Query 。2 、内存分页。当内存分页时,内存容量已经不足,而内存页是与磁盘上的交换区进行交互的。补救的方法是增加更多的内存,减少Oracle SGA 的大小,或者关闭Oracle 的多线程服务器。可以使用各种标准的服务器工
4、具来得到服务器的统计数据,例如vmstat,glance,top 和sar 。 DBA 的目标是确保数据库服务器拥有足够的CPU 和内存资源来处理Oracle 的请求。以下让我们来看一下Oracle 的 row-resequencing 是如何能够极大地减少磁盘I/O 的。Row-resequencing (行的重新排序)就象我们上面提到的,有经验的Oracle DBA 都知道 I/O 是响应时间的最大组成部分。其中磁盘I/O 特别厉害,因为当Oracle 由磁盘上的一个数据文件得到一个数据块时,读的进程就必须等待物理I/O 操作完成。磁盘操作要比数据缓冲慢10,000 倍。因此,如果可以令
5、I/O 最小化,或者减少由于磁盘上的文件竞争而带来的瓶颈,就可以大大地改善名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 1 页,共 17 页 - - - - - - - - - Oracle 数据库的性能。如果系统响应很慢,通过减少磁盘I/O 就可以有一个很快的改善。如果在一个事务中通过按一定的范围搜索primary-key 索引来访问表,那么重新以CTAS 的方法组织表将是你减少 I/O 的首要策略。通过在物理上将行排序为和primary-key 索引一样的顺序,就可以加快获得数
6、据的速度。就象磁盘的负载平衡一样,行的重新排序也是很简单的,而且也很快。通过与其它的DBA 管理技巧一起使用,就可以在高I/O 的系统中大大地减少响应的时间。在高容量的在线事务处理环境中(online transaction processing , OLTP ),数据是由一个 primary 索引得到的,重新排序表格的行就可以令连续块的顺序和它们的primary 索引一样,这样就可以在索引驱动的表格查询中,减少物理I/O 并且改善响应时间。这个技巧仅在应用选择多行的时候有用,或者在使用索引范围搜索和应用发出多个查询来得到连续的 key 时有效。对于随机的唯一primary-key (主键)的
7、访问将不会由行重新排序中得到好处。让我们看一下它是如何工作的。考虑以下的一个SQL 的查询,它使用一个索引来得到 100 行:selectsalaryfromemployeewherelast_name like B%; 这个查询将会使用last_name_index ,搜索其中的每一行来得到目标行。这个查询将会至少使用 100 次物理磁盘的读取,因为employee 的行存放在不同的数据块中。不过,如果表中的行已经重新排序为和last_name_index 的一样,同样的查询又会怎样处理呢?我们可以看到这个查询只需要三次的磁盘I/O 就读完全部100 个员工的资料(一次用作索引的读取,两次用
8、作数据块的读取),减少了97 次的块读取。重新排序带来的性能改善的程度在于在你开始的时候行的乱序性如何,以及你需要由序列中访问多少行。至于一个表中的行与索引的排序键的匹配程度,可以查看数据字典中的dba_indexes 和 dba_tables 视图得到。在 dba_indexes 的视图中,查看clustering_factor 列。如果clustering_factor 的值和表中的块数目大致一样,那么你的表和索引的顺序是一样的。不过,如果clustering_factor 的值接近表中的行数目,那就表明表格中的行和索引的顺序是不一样的。行重新排序的作用是不可以小看的。在需要进行大范围的索
9、引搜索的大表中,行重新排序可以令查询的性能提高三倍。一旦你已经决定重新排序表中的行,你可以使用以下的工具之一来重新组织表格。. 使用 Oracle 的 Create Table As Select (CTAS) 语法来拷贝表格. Oracle9i 自带的表格重新组织工具以下,我们来看以下SQL 语句的调优。SQL 调优Oracle 的 SQL 调优是一个复杂的主题,甚至是需要整本书来介绍Oracle SQL 调优的细微差别。不过有一些基本的规则是每个Oracle DBA 都需要跟从的,这些规则可以改善他们系统的性能。SQL 调优的目标是简单的:. 消除不必要的大表全表搜索:不必要的全表搜索导致
10、大量不必要的I/O ,从而拖慢整个数据库的性能。调优专家首先会根据查询返回的行数目来评价SQL 。在一个有序的表中,如果查询返回少于40% 的行,或者在一个无序的表中,返回少于7% 的行,那么这个查询都可以调整为使用一个索引来代替全表搜索。对于不必要的全表搜索来说,最常见的调优方法是增加索引。可以在表中加入标准的B 树索引,也可以加入bitmap 和基于函数的索引。要决定是否消除一个全表搜索,你可以仔细检查索引搜索的I/O 开销和全表搜索的开销,它们的开销和数据块的读取和可能的并行执行有关,并将两者作对比。在一些情况名师资料总结 - - -精品资料欢迎下载 - - - - - - - - -
11、- - - - - - - - - 名师精心整理 - - - - - - - 第 2 页,共 17 页 - - - - - - - - - 下,一些不必要的全表搜索的消除可以通过强制使用一个index 来达到,只需要在SQL 语句中加入一个索引的提示就可以了。. 在全表搜索是一个最快的访问方法时,将小表的全表搜索放到缓存中,调优专家应该确保有一个专门的数据缓冲用作行缓冲。在Oracle7 中,你可以使用alter table xxx cache 语句,在Oracle8 或以上,小表可以被强制为放到KEEP 池中缓冲。. 确保最优的索引使用:对于改善查询的速度,这是特别重要的。有时Oracle
12、可以选择多个索引来进行查询,调优专家必须检查每个索引并且确保Oracle 使用正确的索引。它还包括 bitmap 和基于函数的索引的使用。. 确保最优的JOIN 操作:有些查询使用NESTED LOOP join 快一些,有些则是HASH join 快一些,另外一些则是sort-merge join 更快。这些规则看来简单,不过它们占SQL 调优任务的90% ,并且它们也无需完全懂得Oracle SQL 的内部运作。以下我们来简单概览以下Oracle SQL 的优化。减少排序我们首先简要查看Oracle 的排序,并且看一看排序操作是如何影响性能的。调整Oracle 的排序操作排序是 SQL 语
13、法中一个小的方面,但很重要,在Oracle 的调整中,它常常被忽略。当使用 create index 、 ORDER BY 或者 GROUP BY 的语句时,Oracle 数据库将会自动执行排序的操作。通常,在以下的情况下Oracle 会进行排序的操作:使用 Order by 的 SQL 语句使用 Group by 的 SQL 语句在创建索引的时候distinct minus union 进行 table join 时,由于现有索引的不足而导致SQL 优化器调用MERGE SORT 当与 Oracle 建立起一个session 时,在内存中就会为该session 分配一个私有的排序区域。如果该
14、连接是一个专用的连接(dedicated connection) ,那么就会根据init.ora 中sort_area_size 参数的大小在内存中分配一个Program Global Area (PGA) 。如果连接是通过多线程服务器建立的,那么排序的空间就在large_pool 中分配。不幸的是,对于所有的session ,用做排序的内存量都必须是一样的,我们不能为需要更大排序的操作分配额外的排序区域。因此,设计者必须作出一个平衡,在分配足够的排序区域以避免发生大的排序任务时出现磁盘排序(disk sorts )的同时,对于那些并不需要进行很大排序的任务,就会出现一些浪费。当然,当排序的空
15、间需求超出了sort_area_size 的大小时,这时将会在TEMP 表空间中分页进行磁盘排序。磁盘排序要比内存排序大概慢14,000 倍。上面我们已经提到,私有排序区域的大小是有init.ora 中的 sort_area_size 参数决定的。每个排序所占用的大小由init.ora 中的 sort_area_retained_size 参数决定。当排序不能在分配的空间中完成时,就会使用磁盘排序的方式,即在Oracle 实例中的临时表空间中进行。磁盘排序的开销是很大的,有几个方面的原因。首先,和内存排序相比较,它们特别慢;而且磁盘排序会消耗临时表空间中的资源。Oracle 还必须分配缓冲池块
16、来保持临时表空间中的块。无论什么时候,内存排序都比磁盘排序好,磁盘排序将会令任务变慢,并且会影响 Oracle 实例的当前任务的执行。还有,过多的磁盘排序将会令free buffer waits 的值变高,从而令其它任务的数据块由缓冲中移走。接着,让我们看一下Oracle 的竞争,并且看一下表的存储参数的设置是如何影响SQL UPDATE 和 INSERT 语句的性能的。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 3 页,共 17 页 - - - - - - - - - 调整Or
17、acle 的竞争Oracle 的其中一个优点时它可以管理每个表空间中的自由空间。Oracle 负责处理表和索引的空间管理,这样就可以让我们无需懂得Oracle 的表和索引的内部运作。不过,对于有经验的Oracle 调优专家来说,他需要懂得Oracle 是如何管理表的extent 和空闲的数据块。对于调整拥有高的insert 或者 update 的系统来说,这是非常重要的。要精通对象的调整,你需要懂得freelists 和 freelist 组的行为,它们和pctfree 及pctused 参数的值有关。这些知识对于企业资源计划(ERP )的应用是特别重要的,因为在这些应用中,不正确的表设置通常
18、是DML 语句执行慢的原因。对于初学者来说,最常见的错误是认为默认的Oracle 参数对于所有的对象都是最佳的。除非磁盘的消耗不是一个问题,否则在设置表的pctfree 和 pctused 参数时,就必须考虑平均的行长和数据库的块大小,这样空的块才会被有效地放到freelists 中。当这些设置不正确时,那些得到的freelists 也是 dead 块,因为它们没有足够的空间来存储一行,这样将会导致明显的处理延迟。Freelists 对于有效地重新使用Oracle 表空间中的空间是很重要的,它和pctfree 及 pctused 这两个存储参数的设置直接相关。通过将pctused 设置为一个高
19、的值,这时数据库就会尽快地重新使用块。不过,高性能和有效地重新使用表的块是对立的。在调整Oracle 的表格和索引时,需要认真考虑究竟需要高性能还是有效的空间重用,并且据此来设置表的参数。以下我们来看一下这些freelists 是如何影响Oracle 的性能的。当有一个请求需要插入一行到表格中时,Oracle 就会到 freelist 中寻找一个有足够的空间来容纳一行的块。你也许知道,freelist 串是放在表格或者索引的第一个块中,这个块也被称为段头(segment header )。 pctfree 和 pctused 参数的唯一目的就是为了控制块如何在 freelists 中进出。虽然
20、freelist link 和 unlink 是简单的Oracle 功能,不过设置freelist link (pctused) 和 unlink (pctfree) 对 Oracle 的性能确实有影响。由 DBA 的基本知识知道,pctfree 参数是控制freelist un-links 的(即将块由freelists 中移除)。设置pctfree=10 意味着每个块都保留10% 的空间用作行扩展。pctused 参数是控制freelist re-links 的。设置pctused=40 意味着只有在块的使用低于40% 时才会回到表格的freelists 中。许多新手对于一个块重新回到fr
21、eelists 后的处理都有些误解。其实,一旦由于一个删除的操作而令块被重新加入到freelist 中,它将会一直保留在freelist 中即使空间的使用超过了 60% ,只有在到达pctfree 时才会将数据块由freelist 中移走。表格和索引存储参数设置的要求总结以下的一些规则是用来设置freelists, freelist groups, pctfree 和 pctused 存储参数的。你也知道,pctused 和 pctfree 的值是可以很容易地通过alter table 命令修改的,一个好的DBA 应该知道如何设置这些参数的最佳值。有效地使用空间和高性能之间是有矛盾的,而表格的
22、存储参数就是控制这个方面的矛盾:. 对于需要有效地重新使用空间,可以设置一个高的pctused 值,不过副作用是需要额外的I/O 。一个高的pctused 值意味着相对满的块都会放到freelist 中。因此,这些块在再次满之前只可以接受几行记录,从而导致更多的I/O 。. 追求高性能的话,可以将pctused 设置为一个低的值,这意味着Oracle 不会将数据块放到 freelists 中直到它几乎是空的。那么块将可以在满之前接收更多的行,因此可以减少插入操作的I/O 。要记住Oracle 扩展新块的性能要比重新使用现有的块高。对于Oracle 来说,扩展一个表比管理freelists 消耗
23、更少的资源。让我们来回顾一下设置对象存储参数的一些常见规则:经常将pctused 设置为可以接收一条新行。对于不能接受一行的free blocks 对于我名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 4 页,共 17 页 - - - - - - - - - 们来说是没有用的。如果这样做,将会令Oracle 的性能变慢,因为Oracle 将在扩展表来得到一个空的块之前,企图读取5 个 dead 的 free block 。表格中chained rows 的出现意味着pctfree 太
24、低或者是db_block_size 太少。在很多情况下,RAW 和 LONG RAW 列都很巨大,以至超过了Oracle 的最大块的大小,这时 chained rows 是不可以避免的。如果一个表有同时插入的SQL 语句,那么它需要有同时删除的语句。运行单一个一个清除的工作将会把全部的空闲块放到一个freelist 中,而没有其它包含有任何空闲块的freelists 出现。 freelist 参数应该设置为表格同时更新的最大值。例如,如果在任何时候,某个表最多有 20 个用户执行插入的操作,那么该表的参数应该设置为freelists=20 。应记住的是freelist groups 参数的值只
25、是对于Oracle Parallel Server 和 Real Application Clusters 才是有用的。对于这类Oracle , freelist groups 应该设置为访问该表格的 Oracle Parallel Server 实例的数目。索引详解什么是索引索引是建立在表的一列或多个列上的辅助对象,目的是加快访问表中的数据;Oracle 存储索引的数据结构是B*树,位图索引也是如此,只不过是叶子节点不同B*数索引;索引由根节点、分支节点和叶子节点组成,上级索引块包含下级索引块的索引数据,叶节点包含索引数据和确定行实际位置的rowid。使用索引的目的加快查询速度减少 I/O
26、操作消除磁盘排序何时使用索引查询返回的记录数排序表 40% 非排序表40%,排序表 7%,建议采用并行机制来提高访问速度,DDS;索引访问。最常用的方法,包括索引唯一扫描和索引范围扫描,OLTP;快速完全索引扫描名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 9 页,共 17 页 - - - - - - - - - 。访问索引中所有数据块,结果相当于全表扫描,可以用索引扫描代替全表扫描,例如:Select serv_id,count(* ) from tg_cdr01 group b
27、y serv_id; 评估全表扫描的合法性如何实现并行扫描。永久并行化(不推荐)alter table customer parallel degree 8; 。单个查询并行化select /*+ full(emp) parallel(emp,8)*/ * from emp; 分区表效果明显优化 SQL 语句排序排序的操作 :。order by 子句。group by 子句。select distinct子句。创建索引时。union 或 minus 。排序合并连接如何避免排序。添加索引。在索引中使用distinct 子句。避免排序合并连接使用提示进行调整使用提示的原则。语法: /*+ hint
28、 */ 。使用表别名 :select /*+ index(e dept_idx)*/ * from emp e 。检验提示常用的提示。rule 。all_rows 。first_rows 。use_nl 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 10 页,共 17 页 - - - - - - - - - 。use_hash 。use_merge 。index 。index_asc 。no_index 。index_desc (常用于使用 max 内置函数)。index_comb
29、ine(强制使用位图索引 ) 。index_ffs(索引快速完全扫描)。use_concat( 将查询中所有 or 条件使用 union all) 。parallel 。noparallel 。full 。ordered(基于成本)调整表连接表连接的类型。等连接where 条件中用等式连接;。外部连接(左、右连接)在 where条件子句的等式谓词放置一个(+)来实现,例如:select a.ename,m from emp a,bonus b where a.ename=b.ename(+); 该语句返回所有emp表的记录;。自连接Select a.value total, B.value h
30、ard, (A.value - b.value) soft , Round(b.value/a.value)*100,1) perc From v$sysstat a,v$sysstat b Where a.statistic# = 179 and B.statistic# = 180; 反连接反连接常用于 not in or not exists 中,是指在查询中找到的任何记录都不包含在结果集中的子查询;不建议使用not in or not exists; 。半连接查询中使用 exists,含义:即使在子查询中返回多条重复的记录,外部查询也只返回一条记录。嵌套循环连接。被连接表中存在索引的情
31、况下使用;。使用 use_nl。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 11 页,共 17 页 - - - - - - - - - hash连接。Hash连接将驱动表加载在内存中,并使用hash技术连接第二个表,提高等连接速度。适合于大表和小表连接;。使用 use_hash 。排序合并连接。排序合并连接不使用索引。使用原则:连接表子段中不存在可用索引;查询返回两个表中大部分的数据快;CBO 认为全表扫描比索引扫描执行的更快。使用 use_merge 使用临时 /中间表多个大表
32、关联时,可以分别把满足条件的结果集存放到中间表,然后用中间表关联;SQL 子查询的调整关联与非关联子查询。关联:子查询的内部引用的是外部表,每行执行一次;。非关联:子查询只执行一次,存放在内存中。调整 not in 和 not exists语句。可以使用外部连接优化not in 子句,例如:select ename from emp where dept_no not in (select dept_no from dept where dept_name =,Math?);改为:select ename from emp,dept where emp.dept_no=dept.dept_no
33、 and dept.dept_name is null; 使用索引调整 SQL Oracle 为什么不使用索引。检查被索引的列或组合索引的首列是否出现在PL/SQL 语句的 WHERE 子句中,这是“ 执行计划 ” 能用到相关索引的必要条件。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 12 页,共 17 页 - - - - - - - - - 。看采用了哪种类型的连接方式。ORACLE 的共有 Sort Merge Join(SMJ)、Hash Join(HJ)和 Nested
34、Loop Join(NL)。在两张表连接,且内表的目标列上建有索引时,只有Nested Loop才能有效地利用到该索引。SMJ 即使相关列上建有索引,最多只能因索引的存在,避免数据排序过程。HJ 由于须做 HASH 运算,索引的存在对数据查询速度几乎没有影响。看连接顺序是否允许使用相关索引。假设表emp的 deptno列上有索引,表 dept 的列deptno上无索引, WHERE 语句有 emp.deptno=dept.deptno条件。在做 NL 连接时, emp做为外表,先被访问,由于连接机制原因,外表的数据访问方式是全表扫描,emp.deptno上的索引显然是用不上,最多在其上做索引全
35、扫描或索引快速全扫描。是否用到系统数据字典表或视图。由于系统数据字典表都未被分析过,可能导致极差的“ 执行计划 ” 。但是不要擅自对数据字典表做分析,否则可能导致死锁,或系统性能下降。索引列是否函数的参数。如是,索引在查询时用不上。是否存在潜在的数据类型转换。如将字符型数据与数值型数据比较,ORACLE 会自动将字符型用 to_number()函数进行转换,从而导致上一种现象的发生。是否为表和相关的索引搜集足够的统计数据。对数据经常有增、删、改的表最好定期对表和索引进行分析,可用SQL 语句“analyze table xxxx compute statistics for all index
36、es;”。ORACLE 掌握了充分反映实际的统计数据,才有可能做出正确的选择。索引列的选择性不高。我们假设典型情况,有表emp,共有一百万行数据,但其中的 emp.deptno列,数据只有 4 种不同的值,如 10、20、30、40。虽然 emp数据行有很多,ORACLE 缺省认定表中列的值是在所有数据行均匀分布的,也就是说每种deptno值各有 25 万数据行与之对应。假设SQL 搜索条件 DEPTNO=10,利用 deptno列上的索引进行数据搜索效率,往往不比全表扫描的高。索引列值是否可为空(NULL )。如果索引列值可以是空值,在SQL 语句中那些要返回 NULL 值的操作,将不会用到
37、索引,如COUNT(*),而是用全表扫描。这是因为索引中存储值不能为全空。看是否有用到并行查询(PQO)。并行查询将不会用到索引。如果从以上几个方面都查不出原因的话,我们只好用采用在语句中加hint 的方式强制ORACLE 使用最优的 “ 执行计划 ” 。hint 采用注释的方式,有行注释和段注释两种方式。如我们想要用到 A 表的 IND_COL1 索引的话,可采用以下方式:“SELECT /*+ INDEX(A IND_COL1 )*/ * FROM A WHERE COL1 = XXX; 如何屏蔽索引语句的执行计划中有不良索引时,可以人为地屏蔽该索引,方法:。数值型:在索引字段上加0,例如
38、select * from emp where emp_no+0 = v_emp_no; 。字符型:在索引字段上加,?,例如名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 13 页,共 17 页 - - - - - - - - - select * from tg_cdr01 where msisdn|?=v_msisdn; 第 3 章SQL 语句处理的过程在调整之前我们需要了解一些背景知识,只有知道这些背景知识,我们才能更好的去调整sql 语句。本节介绍了SQL 语句处理的基本过程
39、,主要包括:查询语句处理 DML 语句处理 (insert, update, delete) DDL 语句处理 (create . , drop . , alter . , ) 事务控制 (commit, rollback) SQL 语句的执行过程(SQL Statement Execution) 在某些情况下,Oracle 运行 sql 的过程可能与下面列出的各个阶段的顺序有所不同。如DEFINE 阶段可能在FETCH 阶段之前,这主要依赖你如何书写代码。对许多 oracle 的工具来说,其中某些阶段会自动执行。绝大多数用户不需要关心各个阶段的细节问题,然而,知道执行的各个阶段还是有必要的,
40、这会帮助你写出更高效的SQL 语句来,而且还可以让你猜测出性能差的SQL 语句主要是由于哪一个阶段造成的,然后我们针对这个具体的阶段,找出解决的办法。DML 语句的处理本节给出一个例子来说明在DML 语句处理的各个阶段到底发生了什么事情。假设你使用Pro*C 程序来为指定部门的所有职员增加工资。程序已经连到正确的用户,你可以在你的程序中嵌入如下的SQL 语句:EXEC SQL UPDATE employees SET salary = 1.10 * salary WHERE department_id = :var_department_id; var_department_id是程序变量,里
41、面包含部门号,我们要修改该部门的职员的工资。当这个SQL 语句执行时,使用该变量的值。每种类型的语句都需要如下阶段:第 1步: Create a Cursor 创建游标第 2 步: Parse the Statement 分析语句第 5 步: Bind Any Variables 绑定变量第 7 步: Run the Statement 运行语句第 9 步: Close the Cursor 关闭游标如果使用了并行功能,还会包含下面这个阶段:第 6 步: Parallelize the Statement 并行执行语句如果是查询语句,则需要以下几个额外的步骤,如图3 所示:第 3 步: Des
42、cribe Results of a Query 描述查询的结果集第 4 步: Define Output of a Query 定义查询的输出数据第 8 步: Fetch Rows of a Query 取查询出来的行下面具体说一下每一步中都发生了什么事情:. 第 1步: 创建游标 (Create a Cursor) 由程序接口调用创建一个游标(cursor )。任何SQL 语句都会创建它,特别在运行DML 语句时,都是自动创建游标的,不需要开发人员干预。多数应用中,游标的创建是自动的。然而,在预编译程序名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - -
43、 - - - - - - 名师精心整理 - - - - - - - 第 14 页,共 17 页 - - - - - - - - - (pro*c) 中游标的创建,可能是隐含的,也可能显式的创建。在存储过程中也是这样的。第 2 步:分析语句 (Parse the Statement) 在语法分析期间,SQL 语句从用户进程传送到Oracle ,SQL 语句经语法分析后,SQL 语句本身与分析的信息都被装入到共享SQL 区。在该阶段中,可以解决许多类型的错误。语法分析分别执行下列操作:翻译 SQL 语句,验证它是合法的语句,即书写正确实现数据字典的查找,以验证是否符合表和列的定义在所要求的对象上获
44、取语法分析锁,使得在语句的语法分析过程中不改变这些对象的定义验证为存取所涉及的模式对象所需的权限是否满足决定此语句最佳的执行计划将它装入共享SQL 区对分布的语句来说,把语句的全部或部分路由到包含所涉及数据的远程节点以上任何一步出现错误,都将导致语句报错,中止执行。只有在共享池中不存在等价SQL 语句的情况下,才对SQL 语句作语法分析。在这种情况下,数据库内核重新为该语句分配新的共享SQL 区,并对语句进行语法分析。进行语法分析需要耗费较多的资源,所以要尽量避免进行语法分析,这是优化的技巧之一。语法分析阶段包含了不管此语句将执行多少次,而只需分析一次的处理要求。Oracle 只对每个 SQL
45、语句翻译一次,在以后再次执行该语句时,只要该语句还在共享SQL 区中,就可以避免对该语句重新进行语法分析,也就是此时可以直接使用其对应的执行计划对数据进行存取。这主要是通过绑定变量(bind variable) 实现的,也就是我们常说的共享SQL ,后面会给出共享SQL 的概念。虽然语法分析验证了SQL 语句的正确性,但语法分析只能识别在SQL 语句执行之前所能发现的错误(如书写错误、权限不足等)。因此,有些错误通过语法分析是抓不到的。例如,在数据转换中的错误或在数据中的错(如企图在主键中插入重复的值)以及死锁等均是只有在语句执行阶段期间才能遇到和报告的错误或情况。查询语句的处理查询与其它类型
46、的SQL 语句不同,因为在成功执行后作为结果将返回数据。其它语句只是简单地返回成功或失败,而查询则能返回一行或许多行数据。查询的结果均采用表格形式,结果行被一次一行或者批量地被检索出来。从这里我们可以得知批量的fetch数据可以降低网络开销,所以批量的fetch也是优化的技巧之一。有些问题只与查询处理相关,查询不仅仅指SELECT语句,同样也包括在其它SQL 语句中的隐含查询。例如,下面的每个语句都需要把查询作为它执行的一部分:INSERT INTO table SELECT. UPDATE table SET x = y WHERE. DELETE FROM table WHERE. CRE
47、ATE table AS SELECT. 具体来说,查询要求读一致性可能使用回滚段作中间处理可能要求SQL 语句处理描述、定义和取数据阶段第 3 步: 描述查询结果(Describe Results of a Query) 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 15 页,共 17 页 - - - - - - - - - 描述阶段只有在查询结果的各个列是未知时才需要;例如,当查询由用户交互地输入需要输出的列名。在这种情况要用描述阶段来决定查询结果的特征(数据类型,长度和名字)
48、。第 4 步: 定义查询的输出数据(Define Output of a Query) 在查询的定义阶段,你指定与查询出的列值对应的接收变量的位置、大小和数据类型,这样我们通过接收变量就可以得到查询结果。如果必要的话,Oracle 会自动实现数据类型的转换。这是将接收变量的类型与对应的列类型相比较决定的。第 5 步: 绑定变量 (Bind Any Variables) 此时, Oracle 知道了 SQL 语句的意思,但仍没有足够的信息用于执行该语句。Oracle 需要得到在语句中列出的所有变量的值。在该例中,Oracle 需要得到对department_id列进行限定的值。得到这个值的过程就
49、叫绑定变量(binding variables) 此过程称之为将变量值捆绑进来。程序必须指出可以找到该数值的变量名(该变量被称为捆绑变量,变量名实质上是一个内存地址,相当于指针)。应用的最终用户可能并没有发觉他们正在指定捆绑变量,因为Oracle 的程序可能只是简单地指示他们输入新的值,其实这一切都在程序中自动做了。因为你指定了变量名,在你再次执行之前无须重新捆绑变量。你可以改变绑定变量的值,而Oracle 在每次执行时,仅仅使用内存地址来查找此值。如果Oracle 需要实现自动数据类型转换的话(除非它们是隐含的或缺省的),你还必须对每个值指定数据类型和长度。关于这些信息可以参考oracle
50、的相关文档,如Oracle Call Interface Programmers Guide 第 6 步: 并行执行语句(Parallelize the Statement ) ORACLE 可以在 SELECTs, INSERTs, UPDATEs, MERGEs, DELETEs语句中执行相应并行查询操作,对于某些DDL 操作,如创建索引、用子查询创建表、在分区表上的操作,也可以执行并行操作。并行化可以导致多个服务器进程(oracle server processes)为同一个SQL 语句工作,使该SQL 语句可以快速完成,但是会耗费更多的资源,所以除非很有必要,否则不要使用并行查询。第