数据库

位置:IT落伍者 >> 数据库 >> 浏览文章

用智能优化限制来提高Oracle性能


发布日期:2021年02月25日
 
用智能优化限制来提高Oracle性能

Oracle SQL运行时间的最主要的组成部分是花在为执行准备新的SQL语句上的时间不过如果了解了可执行计划产生的内在机制你就可以控制Oracle花费在评估表的连接顺序的时间并在总体上提高查询的性能

准备为执行提供的SQL语句

在一个SQL语句进入Oracle库的cache之后而真正被执行之前将会依次发生如下事件

语法检查——检查该SQL语句的拼写和词序是否正确

语义解析——Oracle根据数据词典(data dictionary)来验证所有的表格(table)和列(column)

已保存纲要检查——Oracle检查词典以确认对应该SQL语句是否已存在已保存的纲要(Stored Outline)

产生执行计划——Oracle根据一种罚值(costbased)优化算法和数据词典中的统计数据来决定如何生成最优执行计划

产生二进制代码——Oracle在执行计划的基础上生成可执行的二进制代码

一旦开始准备执行SQL语句上述的过程很快就会执行这是因为Oracle可以识别出同样的SQL语句并对同样的SQL语句重复使用对应的可执行代码然而对产生ad hoc SQL的系统以及SQL中嵌入文本值(literal value)的情况SQL执行计划的生成时间就会变得相当长而且以前的执行计划也常常不能被再次利用对那些牵涉到许多表格的查询Oracle可能要花上很长的时间来决定把连接这些表格的顺序

评估连接表格的顺序

生成可执行计划的时间往往是SQL的准备过程中最大的开销组成部分尤其是在处理有多个表的连接的查询的情况下当Oracle评估表的连接顺序时它必须考虑每一种可能的排序例如当有六个表格需要连接时Oracle需要考虑种(的排列数×××××)可能的连接排序当需要连接的表的数量超过这个排列问题将变得非常突出如果需要连接的表格有那么需要考虑的可能的查询排列顺序超过一万亿种(精确值为

在optimizer_search_limit参数中设置限制

你可以通过optimizer_search_limit参数来控制上述问题的发生该参数用来指定优化器评估的表格连接顺序的最大数目利用这个参数就可以防止优化器在评估所有可能的表格连接顺序中所花费的多余时间如果查询中的表的数量少于或者等于optimizer_search_limit那么优化器检查所有的可能表的连接方式

例如涉及了五个表的查询一共有种(!=××××)可能的连接顺序所以如果参数optimizer_search_limit的值设置为(默认值)那么优化器就会考虑所有的这种可能的连接顺序optimizer_search_limit参数还用来控制启动开始连接指示(star join hint)的阈值当查询所涉及的表格数量少于参数optimizer_search_limit的设定值开始连接指示将被设置

另一个工具optimizer_max_permutations参数

optimizer_max_permutations初始参数用来设定优化器优化范围的上界(即最多考虑多少种表格连接顺序)它依赖于初始参数optimizer_search_limit参数optimizer_max_permutations的默认值为

参数optimizer_search_limit 和optimizer_max_permutations一同用来设置优化器所考虑的排列数的上限优化器不断的产生可能的表的连接的排列直到排列数达到参数optimizer_search_limit或者optimizer_max_permutations为止一旦优化器停止产生新的可能连接排列它将会从中选择出耗费最小的排列

用已排序指示来指定一种连接排序

你可以设定优化器评估的排列数的上限但是对复杂的情况下即使允许的排列数很大优化器也很可能在远远没有找到一个比较合适的排列之间就已经停止优化了你不妨回头看看我前面举的那个例子(个需要连接的表有超过一万亿种排列)如果设定优化器考虑种排列那么这仅仅考虑了所有可能性的优化器极可能没有达到最佳的排列

在Oracle SQL中解决这个问题的最好方法就是手工指定一种表格连接顺序这里需要遵循的大原则就是表格连接顺序应该使得查询计划尽快得以建立通常在SQL语句中使用WHERE限制子句

下面以一个对名为emp的表格的并行查询为例例子中的代码强制查询计划执行一个嵌套循环连接(nested loop join)注意我使用了已排序指示来引导优化器来评估WHERE子句中给出的表格的连接顺序

select /*+ ordered use_nl(bonus) parallel(e ) */

eename

hiredate

m

from

emp e

bonus b

where

eename = bename

;

上面的例子要求优化器按照SQL语句中FROM子句指定的顺序连接表格FROM子句中第一个的表格指定为驱动表格(driving table)已排序指示常常与其它指示联合使用以确保多个表格按照适当的顺序连接起来在遇到涉及四个以上表格的数据仓库查询时常常也是这样处理

下面另给出一个例子在这个例子中我们使用一个已排序指示(ordered hint)来把表格按照一个特定的顺序(先是emp然后是dep和sal最后是bonus)连接起来进一步改进执行计划我指定emp表格到dept表格的连接使用hash连接sal表格到bonus表格使用嵌套循环连接

select /*+ ordered use_hash (emp dept) use_nl (sal bonus) */

from

emp

dept

sal

bonus

where

对实际应用的建议

在实际应用场合下减小optimizer_max_permutations参数并使用已保存的优化计划或者已保存纲要(这样在查询涉及到许多表格时就可以避免重新解析查询所花费的实际)会更有效率一旦找到最好的表格连接顺序你可以手工指定表格的连接顺序(通过已排序指示)并保存纲要这样就永久保存该表格连接顺序

当执行一个新的查询时你可以首先把optimizer_search_limit设置为该查询所涉及的表格数这样优化器将从所有的连接顺序中找出最佳的那种以后执行该查询时你就可以在WHERE子句中按照最佳连接顺序排列表格名称并设置已保存指示和已保存纲要这样就可以按照最佳顺序连接表格而无需重复评估各种可能排序这样查询的速度将会得到显着的提高

已排序指示的优先级高于optimizer_search_limit和 optimizer_max_permutations参数如果设置了已排序指示那么表格就会按照查询命令中的FROM子句给出的顺序连接这样这个过程就没有优化器优化表格的连接顺序这一步骤了

作为Oracle的专业人士你应该知道SQL语句进入库cache中有一个明显的起始延时但是聪明的Oracle数据库管理员以及Oracle开发者能改变表格的搜索限制参数或者利用已排序指示来手工指定表格的连接顺序这样可以极大的降低优化以及执行新查询所花费的时间

上一篇:ORACLE入门之物理文件大小的限制

下一篇:在oracle中运行OS命令