评估SQL查询性能时要比较的指标



我最近观看了一个关于OracleSQL性能调优的在线课程。在视频中,讲师在比较两个查询的性能时,不断比较Autotrace的成本值。

但我也从其他论坛和网站上读到,它指出成本是特定于该查询的相对值,不应用于评估性能的绝对指标。他们建议改为关注一致性获取、物理读取等。

因此,我的解释是,比较用于不同目的的完全不同查询的成本值是没有意义的,因为成本值是相对的。但是当比较相同的2个查询时;"更好的性能";,比较成本值是可以的。我的解释准确吗?

什么时候可以将成本值与其他指标进行比较?

在评估/比较查询性能时,我们还应该考虑哪些其他指标?

通常,我会非常谨慎地比较两个查询之间的cost,除非您有非常具体的理由相信这是有意义的。

一般来说,人们不会考虑优化器为其生成(几乎)最佳计划的99.9%的查询。人们在查询中看到优化器生成了一个明显次优的计划。优化器会产生一个次优计划,原因有两个——要么是它无法将查询转换为可以优化的形式(在这种情况下,人类可能需要重写查询),要么是它用来进行估计的统计数据不正确,所以它认为的最佳计划不是。(当然,查询可能很慢还有其他原因——例如,优化器可能生成了一个最佳计划,但该最佳计划正在进行表扫描,因为缺少索引。)

如果我看到的查询速度很慢,而且查询写得相当好,并且有一组合理的索引可用,那么统计数据最有可能是问题的根源。然而,由于cost完全基于统计数据,这意味着优化器的cost估计是不正确的。如果它们不正确,则cost大致同样可能不正确地高或不正确地低。如果我查看一个查询的查询计划,我知道该查询需要聚合数十万行才能生成报告,并且我看到优化器为它分配了一个个个位数的cost,我知道在这一过程中,它估计一个步骤返回的行太少。为了优化该查询,我将需要cost,以便优化器的估计准确地反映现实。如果我查看一个查询的查询计划,我知道该查询只需要扫描少数几行,并且我看到成千上万的cost,我知道优化器估计某个步骤会返回太多的行。为了优化该查询,我需要降低cost,以便优化器的估计反映实际情况。

如果使用gather_plan_statistics提示,您将在查询计划中看到估计的行数和实际的行数。如果优化器的估计接近现实,那么该计划可能非常好,cost可能相当准确。如果优化器的估计值不正确,则计划可能很差,cost可能是错误的。尝试使用cost度量来调优查询而不首先确认cost与现实相当接近,这很少是非常有效的。

就我个人而言,我会忽略cost,而关注那些可能随着时间的推移而稳定的指标,这些指标实际上与性能相关。我倾向于关注逻辑读取,因为大多数系统都是I/O绑定的,但也可以使用CPU时间或运行时间(不过,运行时间往往不是特别稳定,因为它取决于运行查询时缓存中发生的情况)。如果您正在查看计划,请关注估计的行数与实际的行数,而不是cost

查询的实际运行时间是迄今为止优化查询的最重要指标。99.9%的情况下,我们可以忽略成本和其他指标。

如果查询相对较小且速度较快,并且我们可以很容易地重新运行它,并使用GATHER_PLAN_STATISTICS提示查找实际运行时间:

-- Add a hint to the query and re-run it.
select /*+ gather_plan_statistics */ count(*) from all_objects;
-- Find the SQL_ID of your query.
select sql_id, sql_fulltext
from gv$sql
where lower(sql_text) like '%gather_plan_statistics%'
and sql_text not like '%quine%';
-- Plus in the SQL_ID to find an execution plan with actual numbers.
select * from table(dbms_xplan.display_cursor(sql_id => 'bbqup7krbyf61', format => 'ALLSTATS LAST'));

如果查询非常慢,并且我们无法轻松地重新运行它,请生成SQL监视器报告。这些数据通常在最后一次执行后的几个小时内可用。

-- Generate a SQL Monitor report.
select dbms_sqltune.report_sql_monitor(sql_id => 'bbqup7krbyf61') from dual;

有整本书都是关于解释结果的。最基本的是你想首先检查执行计划,并将重点放在具有最大";A-Time";。如果你想了解查询或优化器哪里出了问题;E-Rows";用";A行";,因为估计的基数驱动了大多数优化器决策。

示例输出:

SQL_ID  bbqup7krbyf61, child number 0
-------------------------------------
select /*+ gather_plan_statistics */ count(*) from all_objects

Plan hash value: 3058112905

--------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                 | Name               | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
--------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                          |                    |      1 |        |      1 |00:00:03.58 |     121K|    622 |       |       |          |
|   1 |  SORT AGGREGATE                           |                    |      1 |      1 |      1 |00:00:03.58 |     121K|    622 |       |       |          |
|*  2 |   FILTER                                  |                    |      1 |        |  79451 |00:00:02.10 |     121K|    622 |       |       |          |
|*  3 |    HASH JOIN                              |                    |      1 |  85666 |  85668 |00:00:00.12 |    1479 |      2 |  2402K|  2402K| 1639K (0)|
|   4 |     INDEX FULL SCAN                       | I_USER2            |      1 |    148 |    148 |00:00:00.01 |       1 |      0 |       |       |          |
...

与工程中的大多数事情一样,这实际上取决于您比较和评估的原因/目的。

COST是Oracle基于时间的一般估计,用作其内部优化器的排名指标。这个答案很好地解释了选择过程。

一般来说,COST作为度量是比较两个不同查询的预期计算时间的好方法,因为它测量查询的估计时间成本,表示为块读取次数。因此,如果您正在比较同一查询的性能,即一个针对时间优化的查询,那么成本是一个很好的衡量标准。

然而,如果您的查询或系统受到时间以外的限制(例如内存效率),那么成本将是一个很难优化的指标。在这种情况下,你应该选择一个与你的最终目标相关的指标。

最新更新