暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

第9章. 快速调优思路

原创 由迪 2021-03-01
618

截至本章,我们基本上已经对所有 SQL 优化及自动调优技术进行了分析和阐述,对于 SQL 的整个执行和处理(包括优化与调优)过程有比较清楚的认识。在此基础上,我们就可以归纳出一套快速调优的思路。
尽管目前存在多种自动调优工具(包括 Oracle 自己的和第三方厂商提供的),而当我们面对各种 SQL 性能问题时,我们不应仅依赖这些工具作为调优的唯一手段。无论是 DBA 还是开发者,我们都需要掌握一些调优手段来帮助快速解决 SQL 性能问题————这些手段或者经验是基于我们对Oracle 的优化器机制、SQL 处理过程的理解的基础上。
实际上,正如我们前面对 Oracle 自动调用工具的分析过程所描述的那样,我们在进行快速调优的时候,也可以从多个方面分析和优化语句。不同的是,优化工具需要对语句的相关信息做全面分 析————这一过程可能会持续较长时间、消耗较大资源,然后才能给出可靠的优化建议。而我们 则是凭借对应用的理解、积累的优化经验以及一些好的优化实践来迅速、低消耗地优化语句。例如, 语句中含有大数据量的表,自动调优工具需要通过对表进行取样收集统计数据,才能保证可靠的优 化建议;而我们作为开发者或者数据库管理员,凭借对系统业务理解和日常开发、维护过程中了解 到的该表信息,就可以估算出其实际的数据量作为我们快速调优的参考。
参考自动调优分析过程,我们也可以从多个方面来快速评估和分析语句的性能,找到瓶颈所在、实施优化措施。
9.1 统计数据检查
由视图(DBA/ALL/USER_TAB_STATISTICS、DBA/ALL/USER_TAB_STATS_HISTORY 等)检查最近统计数据的更新时间。对于数据变化波动较大的表,如果长期没有更新统计数据,其数据可能就会与 实际相差较大、从而导致优化器不能选择最佳执行计划。如果你比较清楚的了解运行在该表上的业 务逻辑的话,就可以根据其当前数据量已经上次更新时间估算出该统计数据是否过期。例如,表 T 是某个模块中记录业务交易相关的额外信息的表,从日常的业务统计中知道,每增加一笔交易,该 表平均增加 5 条记录。从视图的查询结果中知道,该表统计数据的上一次更新时间是 1 个月之前,
当前的数据量为 10 万;而从业务报表中知道,这一个月的业务增长是 1 万笔交易,那么该表在这一个月之内大约会增加 5 万条数据。估算出的数量(15 万)与当前的统计数据相差 50%,说明我们应该重新收集该表的统计数据。
而如果我们不是十分熟悉该表的业务关系,则还可以尝试从其他数据字典视图中找到一些数据进行估算。例如,我们从已有统计数据得到数据记录与使用的数据块数之间的比例关系,然后由当前数据块数估算出当前的数据记录数。
image.png
image.png
image.png
image.png
image.png
扩展统计数据
在 11g 中,如果发现某些字段经常以组合形式出现在谓词条件当中,或者以表达式的方式出现在谓词条件当中,我们可以为它们创建扩展统计数据,帮助优化器选择更好的执行计划。
9.2 从执行计划中找到潜在问题
在执行计划及其相关信息当中,我们可以找到一些导致性能问题的潜在因素,采取对应措施消除问题,使优化器能找到最佳的执行计划。我们在前面章节介绍过多种查看语句执行计划的方法, 其中,DBMS_XPLAN 可以从不同的数据源、根据需要设置输出内容,因此,我们推荐用这种方式查看和分析执行计划。
由 DBMS_XPLAN 输出的执行计划,我们可以从以下几个方法发现语句执行计划的潜在问题。以获取当前缓存内游标的执行计划为例,我们可以指定子游标序号(cursor_child_no)为 NULL,输出缓存内该语句的所有游标的执行计划;指定输出格式(format)为’ADVANCED’,输出全部相关信息; 如果该执行计划还收集到了运行统计数据(例如参数 STATISTICS_LEVLE 为 ALL),则可以加上’LAST
ALLSTATS’输出最后一次运行的统计数据。

9.2.1 是否存在多个游标
通常,在相对稳定的环境当中,每条语句仅有一个子游标存在缓存当中。当发生一些特殊事件时,例如优化器环境的改变、相关对象统计数据变化,会导致当前游标无法被攻陷,优化器需要为 语句重新生成子游标并解析其其执行计划。重新解析出的执行计划可能与原执行计划不同,也意味 着它们之间可能会存在性能差异。我们可以进一步代入绑定变量值、对不同执行计划的性能进行比 较。当我们使用 DBMS_XPLAN 输出的执行计划、并指定游标序号为 NULL 时,会显示出该语句所有子游标的执行计划。

提示:通过视图 V$SQL_SHARED_CURSOR 可以查看语句多个子游标未被共享的原因。11.2.0.2 以后,字段 REASON 给出了描述,对于之前版本,可以通过我们自己创建的视图
ALL_SHARED_CURSORS 显示原因。

我们看以下示例,DBMS_XPLAN 输出结果中,目标语句存在两个子游标、且采用了不同的执行计划。
image.png
image.png
image.png
image.png
image.png
原因,使语句在 CBO 模式下重新解析。通常,导致优化器采用 RBO 模式解析语句的原因有以下几个:

  1. 在语句中嵌入了强制使用 RBO 的提示(RULE);
  2. 优化器环境参数(optimizer_mode)设置了 RBO 模式————由视图
    V$SQL_OPTIMIZER_ENV 可以获得游标解析时的优化器环境,我们需要重点关注其中不为默认值的参数;
  3. 语句中所有对象都没有统计数据存在————如果优化器模式设置为“ALL_ROWS”
    (10.2.0.3 以后的默认设置)会在这种情况下强制使用 CBO;

o cpu costing is off (consider enabling it);
这以注释提醒用户,优化器在解析当前游标的执行计划时,没有考虑 CPU 代价对执行计划的影响。尽管 IO 代价通常是执行计划代价中的主要部分,但是,如果语句中存在对 CPU 消耗较大的操
作时,尤其对复杂结构的语句来说,CPU 代价也是决定优化器是否能找到最佳执行计划的重要因素。通常,造成优化器解析执行计划没有考虑 CPU 代价的原因有以下几个:

  1. 在语句中嵌入了强制关闭 CPU 代价估算的提示(NO_CPU_COSTING);
  2. 优化器环境参数(_optimizer_cost_model)设置出了即计算 IO 代价;
  3. 优化器环境参数(OPTIMIZER_FEATURES_ENABLE)设置了优化器特性低于“9.0.1”;
  4. 用于计算 CPU 代价的系统统计数据不完整;

注意,如果使用 DBMS_XPLAN 显示“EXPLAIN PLAN”命令的结果时,如果采用的 PLAN_TABLE
表是旧版本(9i 之前版本)的结构,由于缺少 CPU_COST 字段,也会出现这一提示。

o dynamic sampling used for this statement (level=N)
这一注释说明优化器在解析当前游标的执行计划时,最少存在一个对象缺少必需的统计数据, 因此优化器通过动态采样获得了该项统计数据。动态采样不仅会增加优化器在解析语句时的资源消 耗,而且其每次解析时获得的统计数据结果都可能不同,从而造成语句性能的不稳定。当执行计划 结果中出现这样的提示时,我们需要同统计数据视图找到语句中缺失数据的对象,对其重新收集统 计数据。

o SQL profile/SQL patch/SQL plan baseline/outline used for this statement
SQL 优化配置等数据是我们通过自动或手工调优后,用于帮助优化器选择我们所希望的执行计
划、进而提高语句性能或保证语句性能稳定性所产生的辅助数据。但是,如果环境发生了较大变化, 例如业务表中某些业务数据大量增长导致相应的统计数据发生较大变化,由这些辅助数据生成的执 行计划就可能不是当前的最佳执行计划。当我们看到发现性能问题的语句的执行计划信息中存在这 样的注释,则需要考虑重新评估这些辅助数据的作用。
9.2.3 存在潜在性能问题的操作
在执行计划当中,某些操作直接或间接的导致语句访问了过多的冗余数据,从而造成语句产生了大量额外开销。我们在检视语句的执行计划时,对这样的操作要特别敏感,分析其在执行计划中 的存在是否合理、是否能找到更好的替代方法来避免不必要的额外开销。
通常来说,当我们发现执行计划中存在以下一些操作时,需要重点关注这些操作、找到产生这 样的操作原因及规避办法。

o Filter
Filter 操作是根据过滤条件,对其子操作获得的数据结果集进行再次过滤,将不满足条件的数据丢弃掉。当执行计划中出现这一操作时,我们要结合其相关谓词信息,分析导致该操作存在的原因、找到消除该操作的办法。

看以下两个例子:
image.png
image.png
这一例子中的过滤谓词表明,由于关联谓词字段允许存在空值,导致执行计划需要有额外的过 滤操作来处理空值,从而导致优化器无法对子查询实施反嵌套(UNNEST)的优化操作。对于这种情况,可以考虑将查询中的 NOT IN 子句改写成 NOT EXISTS,并且增加谓词条件处理空值。

o MERGE JOIN CARTESIAN
笛卡尔合并关联操作会使内外数据集中的每条记录做一次匹配,产生结果集。实际上,笛卡尔关联操作导致的逻辑读次数并不一定很高————不考虑客户端数组大小(Fetch Array Size)的情况下,等于对两个数据集进行扫描所产生的逻辑读次数。并且,其代价计算方法也与等价逻辑关系 的嵌套循环关联一致。但是,这以操作需要借助私有缓存来保持外数据集以完成对内数据集记录的 迭代,这就会造成对私有内存甚至临时磁盘的读写————这些读写次数不会被计入逻辑读当中。 通常,导致笛卡尔合并关联操的原因有以下几个,找到原因后,我们再看是否需要采取措施消除该 操作:
• 表之间不存在关联条件(包括可传递的关联条件)————这通常是语句的逻辑缺陷;
• 内外数据集的基数(Cardinality)都比较小,使得优化器计算出的代价很低,导致选择了该 操作————这种情况下,要注意相关对象的统计数据是否正确。
• ORDERED 提示导致优化器产生笛卡尔积操作————ORDERD 提示会是优化器严格按照
FROM 子句中表的顺序进行关联,如果前后两表之间不存在直接的关联关系,会导致笛卡尔合并关联操。用户需要用其他方式,如使用 LEADING 提示,来消除 OREDED 提示带来的负面影响、并同时满足 ORDERED 提示所需要的效果;
• 不恰当的优化器参数设置会导致优化器选择到不合理的执行计划操作————通过
DBMS_XPLAN 输出的概要数据和 SQL 优化环境视图(V$SQL_OPTIMIZER_ENV)可以找到被修改过的参数;

以下示例是由嵌入语句的 ORDERED 参数导致的笛卡尔合并关联操作:
image.png
image.png
SORT GROUP BY
这一操作时通过排序的方式对数据集分组。而在 10g 之后版本中,引入了哈希分组(HASH GROUP BY)的方法————大多数情况下,哈希分组要求的工作区大小少于排序分组,并且,在工作区自我条件机制下,哈希工作区和排序工作区是共享的。因此,当我们发现执行计划中存在该 操作时,需要检查优化器为什么没有采用哈希分组:
• 是否存在提示强制了分组方法;
• 是否修改了优化器环境参数导致优化器不选择哈希分组;

SORT JOIN
当关联方法为合并排序时,要求内外数据集都已经按照关联字段排序,否则,会增加排序关联操作使数据集排序。当执行计划中出现该操作时,需要检查优化器为什么没有选择其他关联方式:
• 对象统计数据是否正确;
• 是否存在外部强制措施(提示、参数改变、存储概要等)影响优化器行为。

SORT UNIQUE
这一操作时通过排序的方式消除结果集中的重复数据。通常是由 DISTINCT、UNIQUE 或 UNION
等关键字引起的。针对不同情况,采取不同策略进行优化:
• 从逻辑需求角度确认重复值是否是不可容忍的,消除重复数据是否可以放在客户端进行;
• 是否可以借助索引消除排序过程,例如,向现有索引中增加少量字段,使 SORT UNIQUE 转变为 SORT UNIQUE NOSORT 操作;
• UNION 是否可以用 UNION ALL 代替;
• 10g 当中引入哈希唯一(HASH UNIQUE)操作,通过哈希算法来消除重复值。检查是否存在导致优化器未能选择该操作的外在因素;

o 全表扫描(Full Table Scan)
全表扫描会读取表的存储段高水位线以下的所有数据块。不恰当的全表扫描操作不仅会导致语句本身性能的下降,还会导致共享缓存的命中率下降、影响其它查询的性能。从我们前面对全表扫 描执行计划代价计算的分析不难得知,优化器选择全表扫描主要有以下几个原因:
• 不存在除全表扫描以外的访问路径可选择,例如,谓词字段上没有索引、或者索引状态不 可用;
• 错误的统计数据导致优化器放弃索引而对表进行扫描;
• 提示(FULL)或参数(如“_OPTIMIZER_INDEX_COST_ADJ”)设置导致优化器选择全表扫 描而放弃可用的索引;
• 当系统允许并行查询时,优化器会参考对象并行度(创建时设置或者由提示指定)计算代 价,高并行度意味着低的执行计划代价,从而导致选择全表扫描;

以下示例是由于高并行度导致的全表扫描查询:
image.png
image.png
提示:我们在这里要读者特别注意这些操作,并不是要求读者消除这些操作,而是提醒读者,在
SQL 调优过程,着重关注此类操作,分析优化器选择这些操作的原因、以及这样的选择是否合理, 从而提高调优效率。

9.2.4 谓词信息
谓词是查询选择对象数据的依据。不同的谓词会导致优化器选择不同的访问路径来访问数据对象。通过检查执行计划输出中的谓词信息,找到潜在导致优化器不能选择到效率更高的访问路径的 原因。对于谓词信息,我们首先需要关注它是过滤谓词(Filter)还是访问谓词(Access)。
• 过滤谓词意味着当前操作需要对由数据对象或者其子操作返回的数据集进行再次过滤——
——这说明执行计划访问了多余的数据,这些数据在进行过滤谓词匹配时被丢弃;
• 访问谓词是在访问数据对象时的查找条件,仅返回满足条件的数据,访问谓词能利用数据 结构(如索引、ROWID)快速定位到目标数据,避免额外的数据访问;

因此,我们更希望看到访问谓词的出现。我们在执行计划中,尤其是访问对象的操作中发现存 在过滤谓词时,可以从以下几点进行分析,确定过滤谓词是否能转换成更加有效的访问谓词。

谓词选择率
谓词选择率是评估是否需要采用进一步优化措施的重要判断依据。我们可以从执行计划的父子操作返回的基数大小快速判断过滤谓词的选择;也可以参照前面章节的计算方法计算选择率;而如 果条件允许的话,还可以通过直接查询的方法获得。要注意的是,如果谓词(包括过滤谓词和访问 谓词)中存在多个字段上的过滤条件,我们要计算组合条件的选择率。下面示例中,我们分别从执 行计划的统计数据和对表的直接查询计算得到单个和多个过滤条件组合的选择率:
image.png
image.png
image.png
9.2.5 概要数据以及优化器环境检查
DBMS_XPLAN 输出的概要数据是优化器根据当前子游标的最终执行计划生成的。它有一组提示组成,是强制优化器重新该执行计划的必要条件,包括访问路径、关联方式、关联顺序,以及与当 前系统环境不一致的优化器参数等。而如果语句在解析时,某些参数与当前系统默认设置不一致, 导致优化器不能使用某些优化特性。从概要数据中,可以找到这样的提示,进而评估其影响。通常 要关注的提示有:

• OPT_PARAM:修改优化器参数值的提示,例如 OPT_PARAM(‘optimizer_index_cost_adj’ 60);
• OPTIMIZER_FEATURES_ENABLE:设置优化器特性版本的参数,例如
OPTIMIZER_FEATURES_ENABLE(‘10.2.0.4’),我们要关注其设置与当前的 RDBMS 的版本是否一致;

但是,还有一些会影响优化器行为的参数(如“_smm_min_size”)发生变化后不会被包含在
概要数据当中,但是会存在其优化器环境的原始数据(从 VSQL 的 OPTIMIZER_ENV 的字段可看到) 当中。通过视图(VSQL_OPTIMIZER_ENV)或者系统固定表可以看到该游标的执行计划的所有优化 器参数,以及是否为默认值。例如,我们可以通过以下查询检查语句某个子游标的非默认值的参数:
image.png

最后修改时间:2021-03-01 14:59:46
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论