软件部署中常被忽略的性能部署

性能部署是软件部署中一个常常被忽略的地方。尽管确保软件正确部署很重要,但在生产环境中优化性能同样重要。通过在软件部署过程中认识到性能部署的重要性,开发人员可以确保其软件运行良好,并满足用户的需求。关注性能部署可以帮助防止性能问题并提高用户对软件的满意度。

测试数据库与生产数据库之间性能部署的缺失环节
尽管进行了广泛的预部署测试,但在软件性能部署过程中仍有可能在特定的开发环境中遇到性能问题。以下问题可能会出现 :

  1. 无法将生产数据复制到测试数据库中。
  2. 测试数据库与生产数据库之间的硬件和软件配置存在显著差异。
  3. 由于安全限制而无法在生产数据库中测试软件。
  4. 新软件中使用的DML SQL语句可能会损坏生产数据库的数据完整性。

所以用户在发布新应用程序代码后遇到性能问题或应用程序错误并不罕见。

通过预先部署流程确保性能部署
以下说明提供了一种保证软件性能可靠性的新方法。这个想法很简单:由于在生产数据库上运行新的应用程序代码是不可行的,为什么不为生产数据库中的每个SQL语句获取查询计划呢?这样,我们就可以评估每个应用程序代码中的SQL语句在生产数据库上的性能。

假设新应用程序代码中有10个SQL语句需要在测试数据库中识别。在这种情况下,我们需要先清除共享池并在测试数据库中执行新的应用程序,以隔离这10个语句。这个过程将使我们能够捕获和分析这10个SQL语句,并从生产数据库中获取它们的查询计划。下面的表格呈现了查询计划比较所导致的各种潜在结果。

观察结果 可能的原因
生产数据库中有Explain Plan错误 SQL语句需要访问生产数据库中不存在的对象
查询计划有更改 测试和生产数据库之间存在显著的统计差异,包括数据库模式的差异。这些模式差异可能涉及缺少或新的分区以及其他影响数据库结构和组织的变化。由于潜在的重大性能变化,可能需要对SQL进行基准测试。
有未使用的索引 一些在测试数据库中使用的索引在生产数据库中未使用, 由于潜在的重大性能变化,可能需要对SQL进行基准测试
有新使用的索引 一些在生产数据库中使用的索引在测试数据库中未使用, 由于潜在的重大性能变化,可能需要对SQL进行基准测试
总成本有变化 10个SQL语句的整体查询计划成本发生变化。如果生产数据库的数据量大于测试数据库,则成本变化将更高。

DBAO SQL Performance Tracker – YouTube
Tosska DB Ace Enterprise for Oracle – Tosska Technologies Limited

如何使用假设分析来判断数据库环境变化的性能影响 ?

要正确评估数据库环境变化期间一组SQL语句的性能影响,必须深入了解SQL查询性能可能受到的影响。SQL查询可能发生的两种主要性能变化类型。我称之为“渐进性变化”的第一种类型通常是由统计数据的变化引起的,例如相关表或索引页面中数据量的波动。如果统计数据的变化不足以触发新的查询计划,查询计划将保持不变,并且与原始统计数据相比,SQL查询的性能不会有很大的变化。

第二种性能变化类型称为“跳跃性变化”,是由于统计数据或模式发生重大变化而引入新的查询计划。这种类型的变化可能对性能产生重大影响,有时会导致性能灾难。

在更改数据库环境时,必须密切监视SQL查询的性能,并采取适当措施来优化受影响的语句。为了跟踪环境变化前后的关键SQL语句,可以遵循以下一般步骤:

  1. 从SGA或AWR中提取SQL语句以及其查询计划和性能统计信息。
  2. 对数据库应用环境变化,例如创建新索引、收集统计信息、升级数据库或预测在生产数据库中软件部署的性能。
  3. 从更改的数据库环境中获取查询计划。
  4. 比较每个SQL语句的查询计划,以确定是否存在任何差异。
  5. 查找潜在问题,如未使用的索引、高成本SQL更改等。
  6. 对修改后的SQL语句的查询计划进行基准测试,以检测任何性能下降。


如果您只需要跟踪少量SQL语句的性能在环境变化前后的变化,上述步骤可以手动完成。但是,如果您需要监视数百个SQL语句而没有工具,则可能会很具有挑战性。 Tosska DB Ace for Oracle配备了一个强大的工具,可以帮助您跟踪两个数据库之间SQL语句的性能差异。

DBAO SQL Performance Tracker – YouTube
Tosska DB Ace Enterprise for Oracle – Tosska Technologies Limited

如何使用80/20法则来调优数据库应用程序 II ?

之前的文章“如何使用80/20法则来调优数据库应用程序 I”演示了如何应用80/20法则来评估数据库中SQL工作负载的整体性能。在本例中,展示了从Oracle SGA检索到的一组90个SQL语句的图表,每个语句按照其资源使用情况以降序排列列出,最具资源密集型的SQL在左侧。分析显示,大约14.44%的SQL语句占用了80%的总经过时间,而21.11%的SQL语句占用了80%的总CPU时间,表明SQL工作负载分布符合80/20法则。因此,调整SQL可能并不必要,因为这不太可能带来显著的性能改进。

然而,为了更加成本有效地进一步优化数据库性能,建议对高工作量SQL语句的前20%进行深入调查。这将揭示资源利用在前几个SQL语句中急剧下降,使它们成为优化的最关键候选项。


让我们将目标的总资源消耗比例从80%降低到60%,并检查负责利用这些资源的SQL语句。结果很有趣,显示出3个SQL语句占用了60%的经过时间,6个SQL语句占用了60%的CPU时间,而仅有一个SQL语句占用了60%的磁盘读取。通过专注于这些SQL语句,可以提高数据库工作负载高达60%。例如,如果数据库遇到IO瓶颈,专注于一个SQL语句可以节省高达60%的磁盘读取。




您可以利用Excel来进行上述80/20法则分析的模拟,提供SQL工作负载分布的全面概述。这种方法有助于快速评估数据库SQL性能的整体状况,以及优化高负载SQL语句的成本和效益。更进一步的SQL资源频谱分析已集成到我们的Tosska DB Ace for Oracle软件中。

Tosska DB Ace Enterprise for Oracle – Tosska Technologies Limited

DBAO Inspect SQL – YouTube

如何对具有 DB Link 的 Oracle SQL 进行调整 II ?

以下是一个 SQL 示例,查询从远程数据库 @richdb 检索员工、部门和等级表。

SELECT   *
FROM     emp_subsidiary@richdb a,
         department@richdb,
         grade@richdb
WHERE    emp_grade < 1200
         AND emp_dept = dpt_id
         AND emp_grade = grd_id
ORDER BY emp_id

下面是此 SQL 的查询计划,它花费了 15.92 秒才能完成。查询计划的第一步是“SELECT STATEMENT REMOTE”,这意味着整个查询将在远程数据库 @richdb 上执行,并将结果发送回本地数据库。查询计划有点复杂,不容易判断是否最优。但如果查询在本地数据库 @local 上部分执行,我们可以尝试一件事情。

为了请求 Oracle 在本地数据库中执行某些连接操作,SQL 查询必须包含至少一个在本地数据库中执行的表。这才允许在 SQL 查询中使用提示 /*+ DRIVING_SITE ( [ @ queryblock ] tablespec ) */。如果没有表在本地数据库中显式执行,则没有办法请求 Oracle 尝试在本地数据库中执行连接操作。
我们可以在 SQL 中添加一个虚拟条件“EXISTS (SELECT ‘X’ FROM DUAL)”和提示 /*+ DRIVING_SITE(DUAL) */,以强制 Oracle 在本地数据库中执行一些连接操作。

SELECT   /*+ DRIVING_SITE(DUAL) */ *
FROM     emp_subsidiary@richdb a,
         department@richdb,
         grade@richdb
WHERE    emp_grade < 1200
         AND emp_dept = dpt_id
         AND emp_grade = grd_id
         AND EXISTS ( SELECT ‘x’
                      FROM   dual)
ORDER BY emp_id

以下是修改后的 SQL 的查询计划,它花费了 4.08 秒,比原始 SQL 语句快约 4 倍,其中仅有一个连接操作在远程数据库中执行。

在 SQL 查询中添加 ORDERED 提示可以进一步优化查询。这将会将在上一个查询计划中标记的复合语句分解为单个表数据的远程提取,如下面的查询计划所示。

SELECT   /*+ DRIVING_SITE(DUAL) ORDERED */ *
FROM     emp_subsidiary@richdb a,
         department@richdb,
         grade@richdb
WHERE    emp_grade < 1200
         AND emp_dept = dpt_id
         AND emp_grade = grd_id
         AND EXISTS ( SELECT ‘x’
                      FROM   dual)
ORDER BY emp_id

如果您熟悉 Oracle Exadata,您可能会注意到远程数据库 @richdb 中 REMOTE 表的数据检索过程,类似于 Exadata 存储服务器的工作方式。
需要记住的是,将此技术应用于具有 DB Link 的 SQL 查询只在某些环境下有益。例如,当网络速度良好、数据流量不大且本地数据库的工作负载较低时,这种技术是理想的。

Tosska DB Ace for Oracle 可以自动执行此类重写,从而生成一个比原始 SQL 查询快近 10 倍的 SQL 查询。

Tosska DB Ace Enterprise for Oracle – Tosska Technologies Limited

DBAO Tune DB Link SQL – YouTube

如何对具有 DB Link 的 Oracle SQL 进行调整 I ?

这里是一个示例SQL查询,用于计算本地数据库中以字母“D”开头的每个部门在远程数据库@richdb上员工的平均工资。


SELECT   Avg(emp_salary),
         emp_dept
FROM     employee@richdb
WHERE    emp_dept IN (SELECT dpt_id
                      FROM   department
                      WHERE  dpt_name LIKE ‘D%’)
GROUP BY emp_dept

以下是此SQL的查询计划,它需要9.16秒才能完成。查询计划显示从本地DEPARTMENT到远程EMPLOYEE数据库的嵌套循环。由于EMPLOYEE表的大小比DEPARTMENT表大得多,因此在这种情况下,嵌套循环连接路径不是最优的。

为了要求Oracle考虑在远程数据库@richdb中执行连接操作,我添加了一个提示/*+ DRIVING_SITE(employee) */,告诉Oracle使用EMPLOYEE表的数据库@richdb作为分布式查询的驱动站点。


SELECT   /*+ DRIVING_SITE(employee) */ Avg(emp_salary),
         emp_dept
FROM     employee@richdb
WHERE    emp_dept IN (SELECT dpt_id
                      FROM   department
                      WHERE  dpt_name LIKE ‘D%’)
GROUP BY emp_dept

以下查询显示驱动站点已更改为@richdb,并且远程从“本地”数据库检索DEPARTMENT数据。现在速度已经提高到5.94秒。但是查询计划有点复杂,有一个视图,由EMPLOYEE和DEPARTMENT的两个“索引快速完整扫描”的索引哈希连接构成。

我进一步更改了SQL,并在子查询的选择列表中添加了一个虚拟操作Coalesce(dpt_id,dpt_id),以阻止DEMPARTMENT表的索引快速全扫描。


SELECT   /*+ DRIVING_SITE(employee) */ Avg(emp_salary),
         emp_dept
FROM     employee@richdb
WHERE    emp_dept IN (SELECT Coalesce(dpt_id,dpt_id)
                      FROM   department
                      WHERE  dpt_name LIKE ‘D%’)
GROUP BY emp_dept

这个更改给SQL带来了一个新的查询计划,如下所示,性能显著提高至0.71秒。您可以从这个例子中了解虚拟操作Coalesce(dpt_id,dpt_id)如何影响Oracle SQL优化器的决策。

这种重写可以通过Tosska DB Ace for Oracle自动完成,它表明这个重写比原始SQL快了近13倍。

Tosska DB Ace Enterprise for Oracle – Tosska Technologies Limited

如何使用80/20法则来优化数据库应用 I ?

2002年,微软报告称,他们软件中大多数的错误和崩溃都是由他们检测到的少数bug引起的,具体来说大约是20%。这种现象,称为帕累托原理或八二法则,也适用于数据库SQL行为的分析。假定只有20%的SQL语句应该占据整个数据库系统80%的资源消耗。任何应用系统中,少于20%的SQL语句消耗了80%以上的数据库资源,都被认为是异常的,并应进行审查和优化。

使用SQL资源谱分析技术,用户可以设置资源阈值百分比(通常在80%左右)来确定负责大部分资源消耗的前M%的SQL语句。如果分析显示只有少数SQL语句(例如只有4%)负责超过总资源消耗的80%,则表明优化这些特定的SQL语句有可能显著提高整个数据库的性能。

以下的例子显示了从Oracle SGA获取的90个SQL语句集合,每个语句在图表中按其资源使用量列出,从左侧的最高消耗SQL开始以降序排列。分析显示,约14.44%的SQL语句占据了总经过时间的80%,而21.11%的SQL语句占据了总CPU时间的80%。这表明SQL工作负载的分布与80/20法则接近对齐。因此,可能没有急迫的需要进行SQL调优,因为这不太可能导致显着的性能提升。

另一个例子突显了SQL工作负载分布中对80/20法则的显著偏差。分析显示,大约有4个SQL语句占据了总经过时间的80%,而另外4个SQL语句则占据了总CPU时间的80%,还有2个SQL语句贡献了总磁盘读取量的80%。这表明,通过仅优化这4个SQL语句,可以在数据库的整体性能方面实现显著的改进。

您可以利用Excel来进行上述80/20法则分析的模拟,提供SQL工作负载分布的全面概述。这种方法有助于快速评估数据库SQL性能的整体状况,以及优化高负载SQL语句的成本和效益。更进一步的SQL资源谱分析已集成到我们的Tosska DB Ace for Oracle软件中。

Tosska DB Ace Enterprise for Oracle – Tosska Technologies Limited

DBAO Inspect SQL – YouTube

如何让SQL语句运行得更慢…但让用户的体验更好(Oracle)?

您的最终用户可能会不断抱怨他们的数据库应用程序的某些功能运行缓慢,但您可能会发现,在当前的Oracle和硬件配置中,这些SQL语句已经达到了它们的最大速度。除非您愿意升级硬件,否则可能没有办法改进SQL。有时,为了让用户感觉更好,您不必调优SQL以使其运行得更快,而只需调优SQL以使某些应用程序的SQL语句运行得更慢。

这是一个示例,该SQL用于显示表Emp_sal_hist和表Employee在满足某些条件后的信息。该SQL是在线查询执行的,用户必须等待至少5秒,才能在单击鼠标后在屏幕上显示任何数据。

select * from employee a,emp_sal_hist c
where a.emp_name like ‘A%’
and a.emp_id=c.sal_emp_id
and c.sal_salary<1800000
order by c.sal_emp_id

下面是SQL的执行计划和执行统计,提取全部79374条记录花费了10.41秒,第一条记录返回的反应时间为5.72秒。该查询显示了EMPLOYEE和EMP_SAL_HIST表的MERGE JOIN,在将其合并到最终结果之前,对两个相对应的表进行排序操作。这就是用户必须等待至少5秒才能看到屏幕上显示的内容的原因。

作为条件“a.emp_id = c.sal_emp_id”,我们知道“ORDER BY c.sal_emp_id”和“ORDER BY a.emp_id”是等效的,因为SQL语法改写不能强制对该SQL的执行计划进行指定的操作,所以我添加了一个优化器提示/*+ INDEX(@SEL$1 A EMPLOYEE_PK) */来减少“order by a.emp_id”的排序时间。

SELECT   /*+ INDEX(@SEL$1 A EMPLOYEE_PK) */ *
FROM   employee a,
     emp_sal_hist c
WHERE  a.emp_name LIKE ‘A%’
   AND a.emp_id = c.sal_emp_id
   AND c.sal_salary < 1800000
ORDER BY c.sal_emp_id

虽然在新的执行计划中,总体运行时间增加了3秒,但响应时间从5.72秒减少到1.16秒,因此用户可以更快的看到屏幕上第一页信息。我相信大多数用户不在乎是否还有3秒可以返回所有79374条记录。这就是为什么在管理用户期望时,SQL调优更像一门艺术而不是科学。
这种改写可以由Tosska SQL Tuning Expert Pro for Oracle自动实现。

https://www.tosska.cn/tosska-sql-tuning-expert-pro-tse-pro-for-oracle-zh/

如何在不修改源代码的情况下调优Oracle应用程序包的SQL

介绍

应用程序包软件是为授权给第三方组织而开发的软件程序的集合。虽然软件包软件可以通过参数或表来满足用户的特定需求,但软件本身并不是专门为组织开发的。因此,用户不能拥有源代码,也没有方法修改嵌入式SQL语句来进行性能调优。有很多基于Oracle RDBMS的应用程序包,如Siebel、PeopleSoft JD Edwards、SAP等。为了帮助应用程序包的用户,Oracle提供了一些特性来帮助用户调优SQL语句,且不需要更改源代码。

SQL profile

它是由Oracle SQL Tuning Advisor生成的概要文件。SQL概要文件包含对错误估计的统计信息和辅助信息的更正。因此,SQL profile只是将优化器引导到一个更好的计划,但它们并不保证每次解析语句时都使用相同的计划。对于某些SQL语句,无论统计数据有多好,Oracle SQL optimizer仍然无法在特定的环境中生成更好的计划。对于这些类型的SQL语句,人工干预是必要的,但是对于开发人员来说,SQL profile不是一个方便的工具,在不更改程序源代码的情况下,不能强迫Oracle执行新的计划。

SQL plan baselines and stored outlines

由于Oracle环境的变化或Oracle数据库版本升级,它可能会针对Oracle SQL优化器为某些SQL语句生成新的计划。如果它不好,我们需要一些东西来保存旧的计划,以适应新的环境。为了实现SQL计划的稳定性,stored outlines是Oracle数据库早期版本中的主要工具。Oracle数据库11g仍然支持该特性;但是,在将来的版本中,它可能会贬值,并被SQL计划管理所替代。SQL Plan Baselines的机制是保持指定SQL语句的性能,而不管数据库环境的变化或版本升级。此外,还可以手动为SQL语句创建Plan Baselines,并且该技术可以帮助开发人员指导Oracle SQL优化器为性能较差的SQL语句生成特定的计划。因此,当Oracle SQL optimizer下次接收到相同的SQL语句时,将根据数据库中存储的新计划基线组成更好的性能计划。不需要更改源程序中的SQL语句。
例如,如果您想要调优一条执行plan-A计划的SQL(目前Oracle SQL optimizer在您的数据库中使用这条SQL),并且您想要调优这条SQL(带有提示),使Oracle SQL optimizer生成一个新的计划plan-B。你需要做的是用执行调优后的SQL(带新的提示),并使用Oracle提供的以下方法:

使用优化后带提示的SQL执行,并在SGA中缓存plan B。

SET SERVEROUTPUT ON
DECLARE
    My_Plan  PLS_INTEGER;
BEGIN
     My_Plan := DBMS_SPM.load_plans_from_cursor_cache(
              sql_id          => 'Plan-B SQL_ID',
              plan_hash_value => 'Plan-B plan_hash_value’,
              sql_handle      => 'Original SQL’s sql_handle');
      DBMS_OUTPUT.put_line('Plan Loaded=> ' || My_plan);
END;

要启用调优计划,手动将调优后的计划更改为固定计划,方法是将其FIXED属性设置为YES。
要启用SQL plan baselines,请确保optimizer_use_sql_plan_baslines初始化参数设置为TRUE。

使用SQL Plan baselines进行SQL调优的缺点

由于SQL Plan baselines的设计目的是为了在以下环境发生变化后保持SQL语句的性能:

  • 新的优化器版本
  • 更改优化器统计信息和优化器参数
  • 更改schema和元数据定义
  • 更改系统设置
  • SQL profile 创建

您可以看到,它不是为手动SQL调优而设计的。还有一些额外的限制,比如SQL Plan Baselines不支持Parallel Hints,您不能为你的SQL加载一个应用Parallel Hints的Plan-B,而原始计划Plan-A的性能很差。 有时候, Parallel Hints 在Oracle SQL optimizer中往往能生成更好的计划。

SQL Patches

SQL Patches是SQL Repair Advisor提供的特性之一,用于修复SQL语句的关键故障,比如返回错误的结果。 SQL Repair Advisor分析有问题的语句,并在许多情况下建议使用SQL patch来修复该语句。SQL patch将影响Oracle SQL优化器为将来的执行选择一个替代的执行计划,而不是使用原来有问题的执行计划。在Oracle Database 12c Release 2之后,提供了一个公共API来手动创建SQL patch。DBMS_SQLDIAG.CREATE_SQL_PATCH包可以帮助用户为特定的SQL语句创建用于SQL调优的SQL patch。你可以改变一个性能不好的SQL语句的执行计划,而不需要修改程序源代码, 如下:

DECLARE
    Patch_name  VARCHAR2(32767);
BEGIN
    Patch_name := SYS.DBMS_SQLDIAG.create_sql_patch(
        sql_text  => 'SELECT *
                      FROM   employees
                      WHERE  emps_dept IN
                     (SELECT dpts_id
                      FROM   departments
                      WHERE  dpts_avg_salary <200000)', hint_text => 'INDEX(@SEL$1 EMPLOYEES) INDEX(@SEL$2 DEPARTMENTS)',
        name      => 'my_sql_patch_name');
END;

如果数据库版本在Oracle database 12c Release 2之前,则必须使用DBMS_SQLDIAG_INTERNAL.i_create_patch包代替。SQL文本和SQL ID都可以用于SQL提示注入。为SQL注入的提示应该放在hint_text输入参数中。只有一行 Hints 文本可以用于SQL,而且无法为任何子查询块定义自己的查询块名称。因此,如果您的SQL有多个子查询,并且希望指示Oracle在子查询的块中执行某些操作,则必须在注入的 Hints 文本中使用Oracle默认的查询块名称。
hint_text => ‘ INDEX(@SEL$1 EMPLOYEES) INDEX(@SEL$2 DEPARTMENTS) ‘
上面示例中的提示文本显示@SEL$1和@SEL$2是Oracle在SQL执行计划中提供的默认查询块名称。提示告诉Oracle使用索引搜索查询块@SEL$1中的EMPLOYEES表,同时使用索引搜索查询块@SEL$2中的DEPARTMENTS表。

使用SQL Patches来调优SQL的优缺点

没有SQL Plan Baselines的限制,SQL patch更灵活地接受提示指令,带parallel操作的复杂提示通常能被SQL patch接受。在创建 SQL Patches之后,不需要额外的维护工作来告诉Oracle使用 SQL Patches。 Oracle将使用存储的提示优化任何具有相同SQL ID或SQL文本的SQL,并生成更好的性能执行计划。此外,您还可以使用 SQL Patches 来禁用已在包应用程序中写入的破坏性提示的 SQL,甚至使用它来控制一个具有绑定感知的SQL的执行行为。
由于注入的提示文本必须放在一个文本行中,并且只使用默认的查询块名称,因此手工编写一个预期的提示来改进SQL语句,对于大多数SQL开发人员来说是一项困难的任务,尤其是对于包含许多子查询的复杂SQL语句。

一个自动创建Hints和SQL Patches的工具

到目前为止,市场上只有一个工具能够生成更好的提示且完全自动化的方式创建SQL Patch。
Tosska SQL Tuning Expert Pro 是一个用户可以在不接触其程序源代码的情况下提高 SQL 性能的工具。用户可以为不同大小的生产数据库部署不同的性能查询计划,而不需要保存程序源代码的多个版本,并且特别适合于不拥有其应用程序源代码的包应用程序用户。该工具将尝试最有用的提示组合来调优性能较差的SQL语句,最好的提示组合SQL性能将与原始SQL并排进行基准测试。用户将得到准确的性能改进,没有任何猜测或不确定的成本评估。

您可以访问我们的网站了解产品详情
https://www.tosska.cn/tosska-sql-tuning-expert-pro-tse-pro-for-oracle-zh/