2022年性能优化培训文档.doc
Oracle工程部专题知识总结提炼功能优化培训文档 Author:Wenfeng.ZhangCreation Date:五月 4, 2011Last Updated:五月 4, 2011五月 4, 2011Document Ref: Version:DRAFT 1ANote: Title, Subject, Last Updated Date, Reference Number, and Version are marked by a Word Bookmark so that they can be easily reproduced in the header and footer of documents. When you change any of these values, be careful not to accidentally delete the bookmark. You can make bookmarks visible by selecting Tools->OptionsView and checking the Bookmarks option in the Show region.Approvals:Note: To add additional approval lines, press Tab from the last cell in the table above.Note: You can delete any elements of this cover page that you do not need for your document. For example, Copy Number is only required if this is a controlled document and you need to track each copy that you distribute.Document ControlChange Record3日期作者版本变更说明ZHA五月 4, 2011Zhangwenfeng1.0No Previous DocumentReviewers姓名职位Distribution拷贝编号姓名位置/岗位1234Note: The copy numbers referenced above should be written into the Copy Number space on the cover of each distributed copy. If the document is not controlled, you can delete this table, the Note To Holders, and the Copy Number label from the cover page.Note: To update the table of contents, put the cursor anywhere in the table and press F9. To change the number of levels displayed, select the menu option Insert>Index and Tables, make sure the Table of Contents tab is active, and change the Number of Levels to a new value.功能优化简介功能优化 简介本文档主要介绍与SQL调整有关的内容,内容涉及多个方面:SQL语句执行的过程、ORACLE优化器,表之间的关联,如何得到SQL执行计划,如何分析执行计划等内容,从而由浅到深的方式理解SQL优化的过程,使大家逐步步入SQL调整之门,然后你将发觉第1章 SQL语句处理的过程在调整之前我们需要理解一些背景知识,只有明白这些背景知识,我们才能更好的去调整sql语句。 本节介绍了SQL语句处理的根本过程,主要包括: 查询语句处理 DML语句处理(insert, update, delete) DDL 语句处理(create . , drop . , alter . , ) 事务操纵(commit, rollback) SQL 语句的执行过程(SQL Statement Execution) 图3-1 概要的列出了处理和运转一个sql语句的需要各个重要阶段。在某些情况下,Oracle运转sql的过程可能与下面列出的各个阶段的顺序有所不同。如DEFINE阶段可能在FETCH阶段之前,这主要依赖你如何书写代码。 对许多oracle的工具来说,其中某些阶段会自动执行。绝大多数用户不需要关怀各个阶段的细节咨询题,然而,明白执行的各个阶段依然有必要的,这会协助你写出更高效的SQL语句来,而且还能够让你猜想出功能差的SQL语句主要是由于哪一个阶段造成的,然后我们针对这个详细的阶段,找出处理的方法。 7 图 3-1 SQL语句处理的各个阶段 DML语句的处理 本节给出一个例子来说明在DML语句处理的各个阶段到底发生了什么事情。 假设你使用Pro*C程序来为指定部门的所有职员增加工资。程序已经连到正确的用户,你能够在你的程序中嵌入如下的SQL语句: EXEC SQL UPDATE employees SET salary = 1.10 * salary WHERE department_id = :var_department_id; 8 var_department_id是程序变量,里面包含部门号,我们要修正该部门的职员的工资。当这个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步: Describe Results of a Query 描绘查询的结果集 第4步: Define Output of a Query 定义查询的输出数据 第8步: Fetch Rows of a Query 取查询出来的行 下面详细说一下每一步中都发生了什么事情:. 第1步: 创立游标(Create a Cursor) 由程序接口调用创立一个游标(cursor)。任何SQL语句都会创立它,特别在运转DML语句时,都是自动创立游标的,不需要开发人员干涉。多数应用中,游标的创立是自动的。然而,在预编译程序(pro*c)中游标的创立,可能是隐含的,也可能显式的创立。在存储过程中也是如此的。 第2步:分析语句(Parse the Statement) 在语法分析期间,SQL语句从用户进程传送到Oracle,SQL语句经语法分析后,SQL语句本身与分析的信息都被装入到共享SQL区。在该阶段中,能够处理许多类型的错误。 语法分析分别执行以下操作: 翻译SQL语句,验证它是合法的语句,即书写正确 实现数据字典的查找,以验证是否符合表和列的定义 在所要求的对象上获取语法分析锁,使得在语句的语法分析过程中不改变这些对象的定义 验证为存取所涉及的方式对象所需的权限是否满足 9 决定此语句最正确的执行计划 将它装入共享SQL区 对分布的语句来说,把语句的全部或部分路由到包含所涉及数据的远程节点 以上任何一步出现错误,都将导致语句报错,中止执行。 只有在共享池中不存在等价SQL语句的情况下,才对SQL语句作语法分析。在这种情况下,数据库内核重新为该语句分配新的共享SQL区,并对语句进展语法分析。进展语法分析需要消耗较多的资源,因而要尽量防止进展语法分析,这是优化的技巧之一。 语法分析阶段包含了不管此语句将执行多少次,而只需分析一次的处理要求。Oracle只对每个SQL语句翻译一次,在以后再次执行该语句时,只要该语句还在共享SQL区中,就能够防止对该语句重新进展语法分析,也确实是如今能够直截了当使用其对应的执行计划对数据进展存取。这主要是通过绑定变量(bind variable)实现的,也确实是我们常说的共享SQL,后面会给出共享SQL的概念。 尽管语法分析验证了SQL语句的正确性,但语法分析只能识别在SQL语句执行之前所能发觉的错误(如书写错误、权限缺乏等)。因而,有些错误通过语法分析是抓不到的。例如,在数据转换中的错误或在数据中的错(如企图在主键中插入重复的值)以及死锁等均是只有在语句执行阶段期间才能遇到和报告的错误或情况。 查询语句的处理 查询与其它类型的SQL语句不同,由于在成功执行后作为结果将返回数据。其它语句只是简单地返回成功或失败,而查询则能返回一行或许多行数据。查询的结果均采纳表格方式,结果行被一次一行或者批量地被检索出来。从这里我们能够得知批量的fetch数据能够降低网络开销,因而批量的fetch也是优化的技巧之一。 有些咨询题只与查询处理相关,查询不仅仅指SELECT语句,同样也包括在其它SQL语句中的隐含查询。例如,下面的每个语句都需要把查询作为它执行的一部分: INSERT INTO table SELECT. UPDATE table SET x = y WHERE. DELETE FROM table WHERE. CREATE table AS SELECT. 详细来说,查询 要求读一致性 可能使用回滚段作中间处理 可能要求SQL语句处理描绘、定义和取数据阶段 第3步: 描绘查询结果(Describe Results of a Query) 描绘阶段只有在查询结果的各个列是未知时才需要;例如,当查询由用户交互地输入需要输出的列名。在这种情况要用描绘阶段来决定查询结果的特征(数据类型,长度和名字)。 第4步: 定义查询的输出数据(Define Output of a Query) 在查询的定义阶段,你指定与查询出的列值对应的接收变量的位置、大小和数据类型,如此我们通过接收变量就能够得到查询结果。假如必要的话,Oracle会自动实现数据类型的转换。这是将接收变量的类型与对应的列类型相比拟决定的。 10 第5步: 绑定变量(Bind Any Variables) 如今,Oracle明白了SQL语句的意思,但仍没有足够的信息用于执行该语句。Oracle 需要得到在语句中列出的所有变量的值。在该例中,Oracle需要得到对department_id列进展限定的值。得到这个值的过程就叫绑定变量(binding variables) 此过程称之为将变量值捆绑进来。程序必须指出能够找到该数值的变量名(该变量被称为捆绑变量,变量名本质上是一个内存地址,相当于指针)。应用的最终用户可能并没有觉察他们正在指定捆绑变量,由于Oracle 的程序可能只是简单地指示他们输入新的值,事实上这一切都在程序中自动做了。 由于你指定了变量名,在你再次执行之前无须重新捆绑变量。你能够改变绑定变量的值,而Oracle在每次执行时,仅仅使用内存地址来查找此值。 假如Oracle 需要实现自动数据类型转换的话(除非它们是隐含的或缺省的),你还必须对每个值指定数据类型和长度。关于这些信息能够参考oracle的相关文档,如Oracle Call Interface Programmer's Guide 第6步: 并行执行语句(Parallelize the Statement ) ORACLE 能够在SELECTs, INSERTs, UPDATEs, MERGEs, DELETEs语句中执行相应并行查询操作,关于某些DDL操作,如创立索引、用子查询创立表、在分区表上的操作,也能够执行并行操作。并行化能够导致多个效劳器进程(oracle server processes)为同一个SQL语句工作,使该SQL语句能够快速完成,但是会消耗更多的资源,因而除非特别有必要,否则不要使用并行查询。 第7步: 执行语句(Run the Statement) 到了如今这个时候,Oracle拥有所有需要的信息与资源,因而能够真正运转SQL语句了。假如该语句为SELECT查询或INSERT语句,则不需要锁定任何行,由于没有数据需要被改变。然而,假如语句为UPDATE或DELETE语句,则该语句妨碍的所有行都被锁定,防止该用户提交或回滚之前,别的用户对这些数据进展修正。这保证了数据的一致性。 关于某些语句,你能够指定执行的次数,这称为批处理(array processing)。指定执行N次,则绑定变量与定义变量被定义为大小为N的数组的开场位置,这种方法能够减少网络开销,也是优化的技巧之一。 第8步: 取出查询的行(Fetch Rows of a Query) 在fetch阶段,行数据被取出来,每个后续的存取操作检索结果集中的下一行数据,直到最后一行被取出来。上面提到过,批量的fetch是优化的技巧之一。 第9步: 关闭游标(Close the Cursor) SQL语句处理的最后一个阶段确实是关闭游标 DDL语句的处理(DDL Statement Processing) 11 DDL语句的执行不同与DML语句和查询语句的执行,这是由于DDL语句执行成功后需要对数据字典数据进展修正。关于DDL语句,语句的分析阶段实际上包括分析、查找数据字典信息和执行。 事务治理语句、会话治理语句、系统治理语句只有分析与执行阶段,为了重新执行该语句,会重新分析与执行该语句。 事务操纵(Control of Transactions) 一般来说,只有使用ORACLE编程接口的应用设计人员才关怀操作的类型,并把相关的操作组织在一起,构成一个事务。一般来说,我门必须定义事务,如此在一个逻辑单元中的所有工作能够同时被提交或回滚,保证了数据的一致性。一个事务应该由逻辑单元中的所有必须部分组成,不应该多一个,也不应该少一个。 在事务开场和完毕的这段时间内,所有被援用表中的数据都应该在一致的状态(或能够被回溯到一致的状态) 事务应该只包含能够对数据进展一致更改(one consistent change to the data)的SQL语句 例如,在两个帐号之间的转帐(这是一个事务或逻辑工作单元),应该包含从一个帐号中借钱(由一个SQL完成),然后将借的钱存入另一个帐号(由另一个SQL完成)。这2个操作作为一个逻辑单元,应该同时成功或同时失败。其它不相关的操作,如向一个帐户中存钱,不应该包含在这个转帐事务中。 在设计应用时,除了需要决定哪品种型的操作组成一个事务外,还需要决定使用BEGIN_DISCRETE_TRANSACTIO存储过程是否对提高小的、非分布式的事务的功能有作用。 第2章 ORACLE的优化器优化器有时也被称为查询优化器,这是由于查询是妨碍数据库功能最主要的部分,不要以为只有SELECT语句是查询。实际上,带有任何WHERE条件的DML(INSERT、UPDATE、DELETE)语句中都包含查询要求,在后面的文章中,当说到查询时,不一定只是指SELECT语句,也有可能指DML语句中的查询部分。优化器是所有关系数据库引擎中的最神奇、最富挑战性的部件之一,从功能的角度看也是最重要的部分,它功能的高低直截了当关系到数据库功能的好坏。 我们明白,SQL语句同其它语言(如C语言)的语句不一样,它是非过程化(non-procedural)的语句,即当你要取数据时,不需要告诉数据库通过何种途径去取数据,如到底是通过索引取数据,依然应该将表中的每行数据都取出来,然后再通过一一比拟的方式取数据(即全表),这是由数据库的优化器决定的,这确实是非过程化的含义,也确实是说,如何取数据是由优化器决定,而不是应用开发者通过编程决定。在处理SQL的SELECT、UPDATE、INSERT或DELETE语句时,Oracle 必须访咨询语句所涉及的数据,Oracle的优化器部分用来决定访咨询数据的有效途径,使得语句执行所需的I/O和处理时间最小。 为了实现一个查询,内核必须为每个查询定制一个查询策略,或为取出符合条件的数据生成一个执行计划(execution plan)。典型的,关于同一个查询,可能有几个执行计划都符合要求,都能得到符合条件的数据。例如,参与连接的表能够有多种不同的连接方法,这取决于连接条件和优化器采纳的连接方法。为了在多个执行计划中选择最优的执行计划,优化器必须使用一些实际的指标来衡量每个执行计划使用的资源(I/0次数、CPU等),这些资源也确实是我们所说的代价(cost)。假如一个执行计划使用的资源多,我们就说使用执行计划的代价大。以执行计划的代价大小作为衡量标准,优化器选择代价最小的执行计划作为真正执行该查询的执行计划,并抛弃其它的执行计划。 在ORACLE的开展过程中,一共开发过2品种型的优化器:基于规则的优化器和基于代价的优化器。这2种优化器的不同之处关键在于:获得代价的方法与衡量代价的大小不同。现对每种优化器做一下简单的介绍: 基于规则的优化器 - Rule Based (Heuristic) Optimization(简称RBO): 在ORACLE7之前,主要是使用基于规则的优化器。ORACLE在基于规则的优化器中采纳启发式的方法(Heuristic Approach)或规则(Rules)来生成执行计划。例如,假如一个查询的where条件(where clause)包含一个谓词(predicate,事实上确实是一个推断条件,如”=”, “>”, ”<”等),而且该谓词上援用的列上有有效索引,那么优化器将使用索引访咨询这个表,而不考虑其它要素,如表中数据的多少、表中数据的易变性、索引的可选择性等。如今数据库中没有关于表与索引数据的统计性描绘,如表中有多上行,每行的可选择性等。优化器也不考虑实例参数,如multi block i/o、可用排序内存的大小等,因而优化器有时就选择了次优化的计划作为真正的执行计划,导致系统功能不高。 如,关于 select * from emp where deptno = 10; 这个查询来说,假如是使用基于规则的优化器,而且deptno列上有有效的索引,则会通过deptno列上的索引来访咨询emp表。在绝大多数情况下,这是比拟高效的,但是在一些特别情况下,使用索引访咨询也有比拟低效的时候,现举例说明: 13 1) emp表比拟小,该表的数据只存放在几个数据块中。如今使用全表比使用索引访咨询emp表反而要好。由于表比拟小,极有可能数据全在内存中,因而如今做全表是最快的。而假如使用索引,需要先从索引中找到符合条件记录的rowid,然后再一一依照这些rowid从emp中将数据取出来,在这种条件下,效率就会比全表的效率要差一些。 2) emp表比拟大时,而且deptno = 10条件能查询出表中大部分的数据如(50%)。如该表共有4000万行数据,共放在有500000个数据块中,每个数据块为8k,则该表共有约4G,则这么多的数据不可能全放在内存中,绝大多数需要放在硬盘上。如今假如该查询通过索引查询,则是你梦魇的开场。db_file_multiblock_read_count参数的值200。假如采纳全表,则需要500000/db_file_multiblock_read_count=500000/200=2500次I/O。但是假如采纳索引,假设deptno列上的索引都已经cache到内存中,因而能够将访咨询索引的开销忽略不计。由于要读出4000万x 50% = 2000万数据,假设在读这2000万数据时,有99.9%的命中率,则依然需要20000次I/O,比上面的全表需要的2500次多多了,因而在这种情况下,用索引反而功能会差特别多。在如此的情况下,用全表的时间是固定的,但是用索引的时间会随着选出数据的增多使查询时间相应的延长。 上面是单调的假设数据,如今以详细的实例给予验证: 环境: oracle 817 + linux + 阵列柜,表SWD_BILLDETAIL有3200多万数据; 表的id列、cn列上都有索引 经查看执行计划,发觉执行select count(id) from SWD_BILLDETAIL;使用全表,执行完用了大约1.50分钟(4次执行取平均,每次分别为1.45 1.51 2.00 1.46)。而执行select count(id) from SWD_BILLDETAIL where cn <'6'却用了2个小时还没有执行完,经分析该语句使用了cn列上的索引,然后利用查询出的rowid再从表中查询数据。我为什么不使用select count(cn) from SWD_BILLDETAIL where cn <'6'呢?后面在分析执行途径的索引时时会给出说明。 下面确实是基于规则的优化器使用的执行途径与各个途径对应的等级: RBO Path 1: Single Row by Rowid(等级最高) RBO Path 2: Single Row by Cluster Join RBO Path 3: Single Row by Hash Cluster Key with Unique or Primary Key RBO Path 4: Single Row by Unique or Primary Key RBO Path 5: Clustered Join RBO Path 6: Hash Cluster Key RBO Path 7: Indexed Cluster Key RBO Path 8: Composite Index RBO Path 9: Single-Column Indexes RBO Path 10: Bounded Range Search on Indexed Columns RBO Path 11: Unbounded Range Search on Indexed Columns RBO Path 12: Sort Merge Join RBO Path 13: MAX or MIN of Indexed Column RBO Path 14: ORDER BY on Indexed Column RBO Path 15: Full Table Scan(等级最低) 上面的执行途径中,RBO认为越往下执行的代价越大,即等级越低。在RBO生成执行计划时,假如它发觉有等级高的执行途径可用,则确信会使用等级高的途径,而不管任何其它妨碍功能的元素,即RBO通过上面的途径的等级决定执行途径的代价,执行途径的等级越高,则使用该执行途径的代价越小。如上面2个例子所述,假如使用RBO,则确信使 14 用索引访咨询表,也确实是选择了比拟差的执行计划,如此会给数据库功能带来特别大的负面妨碍。为理处理这个咨询题,从ORACLE 7开场oracle引入了基于代价的优化器,下面给出了介绍。 基于代价的优化器 - Cost Based Optimization(简称CBO) Oracle把一个代价引擎(Cost Engine)集成到数据库内核中,用来可能每个执行计划需要的代价,该代价将每个执行计划所消耗的资源进展量化,从而CBO能够依照这个代价选择出最优的执行计划。一个查询消耗的资源能够被分成3个根本组成部分:I/O代价、CPU代价、network代价。I/O代价是将数据从磁盘读入内存所需的代价。访咨询数据包括将数据文件中数据块的内容读入到SGA的数据高速缓存中,在一般情况下,该代价是处理一个查询所需要的最主要代价,因而我们在优化时,一个根本原则确实是降低查询所产生的I/O总次数。CPU代价是处理在内存中数据所需要的代价,如一旦数据被读入内存,则我们在识别出我们需要的数据后,在这些数据上执行排序(sort)或连接(join)操作,这需要消耗CPU资源。 关于需要访咨询跨节点(即通常说的效劳器)数据库上数据的查询来说,存在network代价,用来量化传输操作消耗的资源。查询远程表的查询或执行分布式连接的查询会在network代价方面花费比拟大。 在使用CBO时,需要有表和索引的统计数据(分析数据)作为根底数据,有了这些数据,CBO才能为各个执行计划计算出相对精确的代价,从而使CBO选择最正确的执行计划。因而定期的对表、索引进展分析是绝对必要的,如此才能使统计数据反映数据库中的真实情况。否则就会使CBO选择较差的执行计划,妨碍数据库的功能。分析操作不必做的太频繁,一般来说,每星期一次就足够了。切记假如想使用CBO,则必须定期对表和索引进展分析。 关于分析用的命令,随着数据库版本的晋级,用的命令也发生了变换,在oracle 8i往常,主要是用ANALYZE命令。在ORACLE 8I以后,又引入了DBMS_STATS存储包来进展分析。幸运的是从ORACLE 10G以后,分析工作变成自动的了,这减轻的DBA的负担,不过在一些特别情况下,还需要一些手工分析。 假如采纳了CBO优化器,而没有对表和索引进展分析,没有统计数据,则ORACLE使用缺省的统计数据(至少在ORACLE 9I中是如此),这能够从oracle的文档上找到。使用的缺省值确信与系统的实际统计值不一致,这可能会导致优化器选择错误的执行计划,妨碍数据库的功能。 要留意的是:尽管CBO的功能随着ORACLE新版本的推出,功能越来越强,但它不是能包治百病的神药,否则就不再需要DBA了,那我就惨了!实际上任何一个语句,随着硬件环境与应用数据的不同,该语句的执行计划可能需要随之发生变化,如此才能获得最好的功能。因而有时候不在详细的环境下而进展SQL功能调整是徒劳的。 在ORACLE8I推出的时候,ORACLE竭力建议大家使用CBO,说CBO有种种好处,但是在那是ORACLE开发的应用系统依然使用基于规则的优化器,从这件事上我们能够得出如此的结论:1) 假如团队的数据库水平特别高而且都熟悉应用数据的特点,RBO也能够获得特别好的功能。2)CBO不是特别稳定,但是一个比拟有前途的优化器,Oracle竭力建议大家用是为了让大家尽快发觉它的BUG,以便进一步改善,但是ORACLE为了对本人开发的应用系统负责,他们依然使用了比拟熟悉而且成熟的RBO。从这个事情上给我们的启发确实是:我们在以后的开发中,应该尽量采纳我们熟悉同时成熟的技术,而不要一味的采纳新技术,一味采纳新技术并不一定能开发出好的产品。幸运的是从ORACLE 10G后,CBO已经足够的强大与智能,大家能够放心的使用该技术,由于ORACLE 10G后,Oracle本人开发的应用系统也使用CBO优化器了。而且ORACLE规定,从ORACLE 10G开场,开场废弃RBO优化器。这句话并不是指在ORACLE 10G中不能使用RBO,而是从ORACLE 15 10G开场开场,不再为RBO的BUG提供修补效劳。 在上面的第2个例子中,假如采纳CBO优化器,它就会考虑emp表的行数,deptno列的统计数据,发觉对该列做查询会查询出过多的数据,同时考虑db_file_multiblock_read_count参数的设置,发觉用全表的代价比用索引的代价要小,从而使用全表从而获得良好的执行功能。 推断当前数据库使用何种优化器: 主要是由optimizer_mode初始化参数决定的。该参数可能的取值为:first_rows_1 | 10 | 100 | 1000 | first_rows | all_rows | choose | rule。详细解释如下: RULE为使用RBO优化器。 CHOOSE则是依照实际情况,假如数据字典中包含被援用的表的统计数据,即援用的对象已经被分析,则就使用CBO优化器,否则为RBO优化器。 ALL_ROWS为CBO优化器使用的第一种详细的优化方法,是以数据的吞吐量为主要目的,以便能够使用最少的资源完成语句。 FIRST_ROWS为优化器使用的第二种详细的优化方法,是以数据的响应时间为主要目的,以便快速查询出开场的几行数据。 FIRST_ROWS_1 | 10 | 100 | 1000 为优化器使用的第三种详细的优化方法,让优化器选择一个能够把响应时间减到最小的查询执行计划,以迅速产生查询结果的前 n 行。该参数为ORACLE 9I新引入的。 从ORACLE V7以来,optimizer_mode参数的缺省设置应是"choose",即假如对已分析的表查询的话选择CBO,否则选择RBO。在此种设置中,假如采纳了CBO,则缺省为CBO中的all_rows方式。 留意:即便指定数据库使用RBO优化器,但有时ORACLE数据库依然会采纳CBO优化器,这并不是ORACLE的BUG,主要是由于从ORACLE 8I后引入的许多新特性都必须在CBO下才能使用,而你的SQL语句可能正好使用了这些新特性,如今数据库会自动转为使用CBO优化器执行这些语句。 什么是优化 优化是选择最有效的执行计划来执行SQL语句的过程,这是在处理任何数据的语句(SELECT,INSERT,UPDATE或DELETE)中的一个重要步骤。对Oracle来说,执行如此的语句有许多不同的方法,譬如说,将随着以什么顺序访咨询哪些表或索引的不同而不同。所使用的执行计划能够决定语句能执行得有多快。Oracle中称之为优化器(Optimizer)的组件用来选择这种它认为最有效的执行计划。 由于一系列要素都会会妨碍语句的执行,优化器综合权衡各个要素,在众多的执行计划中选择认为是最正确的执行计划。然而,应用设计人员通常比优化器更明白关于特定应用的数据特点。不管优化器多么智能,在某些情况下开发人员能选择出比优化器选择的最优执行计划还要好的执行计划。这是需要人工干涉数据库优化的主要缘故。事实说明,在某些情况下,确实需要DBA对某些语句进展手工优化。 注:从Oracle的一个版本到另一个版本,优化器可能对同一语句生成不同的执行计划。在今后的Oracle 版本中,优化器可能会基于它能够用的更好、更理想的信息,作出更优的决策,从而导致为语句产生更优的执行计划。第3章 ORACLE的执行计划背景知识: 为了更好的进展下面的内容我们必须理解一些概念性的术语: 共享sql语句 为了不重复解析一样的SQL语句(由于解析操作比拟费资源,会导致功能下降),在第一次解析之后,ORACLE将SQL语句及解析后得到的执行计划存放在内存中。这块位于系统全局区域SGA(system global area)的共享池(shared buffer pool)中的内存能够被所有的数据库用户共享。因而,当你执行一个SQL语句(有时被称为一个游标)时,假如该语句和之前的执行过的某一语句完全一样,同时之前执行的该语句与其执行计划仍然在内存中存在,则ORACLE就不需要再进展分析,直截了当得到该语句的执行途径。ORACLE的这个功能大大地提高了SQL的执行功能并大大节约了内存的使用。使用这个功能的关键是将执行过的语句尽可能放到内存中,因而这要求有大的共享池(通过设置shared buffer pool参数值)和尽可能的使用绑定变量的方法执行SQL语句。 当你向ORACLE 提交一个SQL语句,ORACLE会首先在共享内存中查找是否有一样的语句。这里需要注明的是,ORACLE对两者采取的是一种严格匹配,要达成共享,SQL语句必须完全一样(包括空格,换行等)。 下面是推断SQL语句是否与共享内存中某一SQL一样的步骤: 1). 对所发出语句的文本串进展hashed。假如hash值与已在共享池中SQL语句的hash值一样,则进展第2步: 2) 将所发出语句的文本串(包括大小写、空白和注释)与在第步中识别的所有 已存在的SQL语句相比拟。 例如: SELECT * FROM emp WHERE empno = 1000; 和以下每一个都不同 SELECT * from emp WHERE empno = 1000; SELECT * FROM EMP WHERE empno = 1000; SELECT * FROM emp WHERE empno = 2000; 在上面的语句中列值都是直截了当SQL语句中的,今后我们将这类sql成为硬编码SQL 或字面值SQL 使用绑定变量的SQL语句中必须使用一样的名字的绑定变量(bind variables) , 例如: a. 该2个sql语句被认为一样 select pin , name from people where pin = :blk1.pin; select pin , name from people where pin = :blk1.pin; b. 该2个sql语句被认为不一样 select pin , name from people where pin = :blk1.ot_ind; select pin , name from people where pin = :blk1.ov_ind; 今后我们将上面的这类语句称为绑定变量SQL。 17 3). 将所发出语句中涉及的对象与第步中识别的已存在语句所涉及对象相比拟。 例如: 如用户user1与用户user2下都有EMP表,则 用户user1发出的语句:SELECT * FROM EMP; 与 用户user2发出的语句:SELECT * FROM EMP; 被认为是不一样的语句, 由于两个语句中援用的EMP不是指同一个表。 4). 在SQL语句中使用的捆绑变量的捆绑类型必须一致。 假如语句与当前在共享池中的另一个语句是等同的话,Oracle并不对它进展语法分析。而直截了当执行该语句,提高了执行效率,由于语法分析比拟消耗资源。 留意的是,从oracle 8i开场,新引入了一个CURSOR_SHARING参数,该参数的主要目的确实是为理处理在编程过程中已大量使用的硬编码SQL咨询题。由于在实际开发中,特别多程序人员为了提高开发速度,而采纳类似下面的开发方法: str_sql string; int_empno int; int_empno = 2000;