SQL调优指南笔记13:Gathering Optimizer Statistics

Posted dingdingfish

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQL调优指南笔记13:Gathering Optimizer Statistics相关的知识,希望对你有一定的参考价值。

本文为SQL Tuning Guide第13章“Gathering Optimizer Statistics”的笔记。

重要基本概念

  • cost
    A numeric internal measure that represents the estimated resource usage for an execution plan. The lower the cost, the more efficient the plan.
    一个数字内部度量,表示执行计划的估计资源使用情况。 成本越低,计划越有效。

本章说明如何使用 DBMS_STATS.GATHER_*_STATS 程序单元。

13.1 Configuring Automatic Optimizer Statistics Collection

Oracle 数据库可以自动收集优化器统计信息。

13.1.1 About Automatic Optimizer Statistics Collection

自动维护任务基础结构(称为 AutoTask)安排任务在称为维护窗口的 Oracle 调度程序窗口中自动运行。

自动和手动统计收集之间的区别

主要区别在于自动收集优先考虑需要统计信息的数据库对象。 在维护窗口关闭之前,自动收集会评估所有对象并优先考虑没有统计信息或非常旧的统计信息的对象。

手动收集统计信息时,您可以使用 DBMS_AUTO_TASK_IMMEDIATE 包重现自动收集的对象优先级。 这个包运行在自动夜间统计收集作业期间执行的相同统计收集作业。

自动统计信息收集的工作原理

自动优化器统计信息收集作为 AutoTask 的一部分运行。 默认情况下,该集合在所有预定义的维护时段中运行。 为一周中的每一天安排一个窗口。

为了收集优化器统计信息,数据库调用一个内部过程,该过程与带有 GATHER AUTO 选项的 GATHER_DATABASE_STATS 过程类似。 自动统计收集尊重数据库中设置的所有首选项。

当自动优化器统计信息收集任务为 PDB 收集数据时,它会将这些数据存储在 PDB 中。 如果拔下 PDB,则包含此数据。 当前容器为 CDB 根的普通用户可以查看 PDB 的优化器统计数据。 当前容器是 PDB 的用户只能查看 PDB 的优化器统计数据。

13.1.2 Configuring Automatic Optimizer Statistics Collection Using Cloud Control

您可以使用 Cloud Control 启用和禁用所有自动维护任务,包括自动优化器统计信息收集。

默认窗口时间适用于大多数情况。 但是,您可能会在窗口期间进行批量加载等操作。 在这种情况下,为避免与自动统计收集同时发生的操作导致的潜在冲突,Oracle 建议您相应地更改窗口。

13.1.3 Configuring Automatic Optimizer Statistics Collection from the Command Line

如果您不使用 Cloud Control 来配置自动优化器统计信息收集,那么您必须使用命令行。

您有以下选择:

  • 运行 DBMS_AUTO_TASK_ADMIN PL/SQL 包中的 ENABLE 或 DISABLE 过程。
    这个包是推荐的命令行技术。 对于 ENABLE 和 DISABLE 过程,您可以使用 window_name 参数指定特定的维护时段。
  • 将 STATISTICS_LEVEL 初始化级别设置为 BASIC 以禁用所有建议和统计信息的收集,包括 Automatic SQL Tuning Advisor。
    注意:由于禁用了监控和许多自动功能,Oracle 强烈建议您不要将 STATISTICS_LEVEL 设置为 BASIC。

启用自动化任务:

BEGIN
  DBMS_AUTO_TASK_ADMIN.ENABLE (  
    client_name  => 'auto optimizer stats collection'
,   operation    => NULL
,   window_name  => NULL 
);
END;
/

禁用自动化任务:

BEGIN
  DBMS_AUTO_TASK_ADMIN.DISABLE (  
    client_name  => 'auto optimizer stats collection'
,   operation    => NULL
,   window_name  => NULL 
);
END;
/

查询自动化任务:

COL CLIENT_NAME FORMAT a31

SELECT CLIENT_NAME, STATUS
FROM   DBA_AUTOTASK_CLIENT;
-- WHERE  CLIENT_NAME = 'auto optimizer stats collection';
CLIENT_NAME                     STATUS
------------------------------- --------
auto optimizer stats collection ENABLED 
auto space advisor              ENABLED 
sql tuning advisor              ENABLED

更改自动统计收集的窗口属性,例如,要更改周一维护时段,使其从早上 5 点开始:

BEGIN 
  DBMS_SCHEDULER.SET_ATTRIBUTE (
    'MONDAY_WINDOW'
,   'repeat_interval'
,   'freq=daily;byday=MON;byhour=05;byminute=0;bysecond=0'
);
END;
/

13.2 Configuring High-Frequency Automatic Optimizer Statistics Collection

这个轻量级任务补充了标准的自动统计收集。这是19c开始支持的Exadata独有特性。

alter system set "_exadata_feature_on"=true scope=spfile;
shutdown immediate;
startup;

13.2.1 About High-Frequency Automatic Optimizer Statistics Collection

您可以将自动统计信息收集配置为更频繁地发生。

高频自动优化器统计收集的目的

AutoTask 安排任务在维护窗口中自动运行。 默认情况下,为一周中的每一天安排一个窗口。 自动优化器统计信息收集 (DBMS_STATS) 在所有预定义的维护窗口中运行。

统计信息可能在两个连续的统计信息收集任务之间过时。 如果数据频繁更改,陈旧的统计信息可能会导致性能问题。 例如,一家经纪公司可能会在交易时间内收到大量数据,导致优化器在此期间执行的查询使用陈旧的统计数据。

高频自动优化器统计信息收集补充了标准统计信息收集作业。 默认情况下,收集每 15 分钟发生一次,这意味着统计信息的陈旧时间更短。

高频自动优化器统计信息收集的工作原理

要启用和禁用高频任务、设置执行间隔和设置最大运行时间,请使用 DBMS_STATS.SET_GLOBAL_PREFS 过程。 高频任务是“轻量级的”,只收集陈旧的统计数据。 它不执行诸如清除不存在对象的统计信息或调用 Optimizer Statistics Advisor 之类的操作。 标准自动化作业执行这些附加任务。

在维护窗口中运行的自动统计收集作业不受高频作业的影响。 高频任务可能会在维护窗口执行,但不会在维护窗口自动统计收集作业执行时执行。 您可以通过查询 DBA_AUTO_STAT_EXECUTIONS 来监控任务。

13.2.2 Setting Preferences for High-Frequency Automatic Optimizer Statistics Collection

要启用和禁用任务,请使用 DBMS_STATS.SET_GLOBAL_PREFS。

您可以使用 DBMS_STATS.SET_GLOBAL_PREFS 将首选项设置为以下任何值:

  • AUTO_TASK_STATUS
    启用或禁用高频自动优化器统计信息收集。 值为:
    • ON — 启用高频自动优化器统计信息收集。
    • OFF — 禁用高频自动优化器统计信息收集。 这是默认设置。
  • AUTO_TASK_MAX_RUN_TIME
    配置执行高频自动优化器统计信息收集的最大运行时间(以秒为单位)。 最大值为 3600(等于 1 小时),这是默认值。
  • AUTO_TASK_INTERVAL
    指定执行高频自动优化器统计信息收集的时间间隔(以秒为单位)。 最小值为 60。默认值为 900(等于 15 分钟)。

要配置高频任务,您必须具有管理员权限。

示例:

-- 启用高频自动任务
EXEC DBMS_STATS.SET_GLOBAL_PREFS('AUTO_TASK_STATUS','ON');
-- 将最长运行时间设置为 10 分钟
EXEC DBMS_STATS.SET_GLOBAL_PREFS('AUTO_TASK_MAX_RUN_TIME','600');
-- 将频率设置为 8 分钟
EXEC DBMS_STATS.SET_GLOBAL_PREFS('AUTO_TASK_INTERVAL','240');

13.2.3 High-Frequency Automatic Optimizer Statistics Collection: Example

在此示例中,您运行 DML 语句,然后启用高频统计收集作业。

此示例假定以下内容:

  • 您以管理员身份登录到数据库。
  • sh 模式的统计信息是最新的。 exec dbms_stats.gather_schema_stats('SH');
  • 高频自动优化器统计信息收集未启用。
SET LINESIZE 170
SET PAGESIZE 5000
COL TABLE_NAME FORMAT a20
COL PARTITION_NAME FORMAT a20
COL NUM_ROWS FORMAT 9999999
COL STALE_STATS FORMAT a3

SELECT TABLE_NAME, PARTITION_NAME, NUM_ROWS, STALE_STATS
FROM   DBA_TAB_STATISTICS
WHERE  OWNER = 'SH'
AND    TABLE_NAME IN ('CUSTOMERS','SALES')
ORDER BY TABLE_NAME, PARTITION_NAME;

TABLE_NAME           PARTITION_NAME       NUM_ROWS STA
-------------------- -------------------- -------- ---
CUSTOMERS                                    55500 NO 
SALES                SALES_1995                  0 NO 
SALES                SALES_1996                  0 NO 
SALES                SALES_H1_1997               0 NO 
SALES                SALES_H2_1997               0 NO 
SALES                SALES_Q1_1998           43687 NO 
SALES                SALES_Q1_1999           64186 NO 
SALES                SALES_Q1_2000           62197 NO 
SALES                SALES_Q1_2001           60608 NO 
SALES                SALES_Q1_2002               0 NO 
SALES                SALES_Q1_2003               0 NO 
SALES                SALES_Q2_1998           35758 NO 
SALES                SALES_Q2_1999           54233 NO 
SALES                SALES_Q2_2000           55515 NO 
SALES                SALES_Q2_2001           63292 NO 
SALES                SALES_Q2_2002               0 NO 
SALES                SALES_Q2_2003               0 NO 
SALES                SALES_Q3_1998           50515 NO 
SALES                SALES_Q3_1999           67138 NO 
SALES                SALES_Q3_2000           58950 NO 
SALES                SALES_Q3_2001           65769 NO 
SALES                SALES_Q3_2002               0 NO 
SALES                SALES_Q3_2003               0 NO 
SALES                SALES_Q4_1998           48874 NO 
SALES                SALES_Q4_1999           62388 NO 
SALES                SALES_Q4_2000           55984 NO 
SALES                SALES_Q4_2001           69749 NO 
SALES                SALES_Q4_2002               0 NO 
SALES                SALES_Q4_2003               0 NO 
SALES                                       918843 NO 

30 rows selected. 

以上输出显示没有任何统计信息是陈旧的。

对销售和客户表执行 DML:

-- insert 918,843 rows in sales
INSERT INTO sh.sales SELECT * FROM sh.sales;
-- update around 29% of sales rows  (271,338)
UPDATE sh.sales SET amount_sold = amount_sold + 1 WHERE amount_sold > 100;
-- insert 1 row into customers
INSERT INTO sh.customers(cust_id, cust_first_name, cust_last_name, 
    cust_gender, cust_year_of_birth, cust_main_phone_number,  
    cust_street_address, cust_postal_code, cust_city_id, 
    cust_city, cust_state_province_id, cust_state_province, 
    country_id, cust_total, cust_total_id) 
  VALUES(188710, 'Jenny', 'Smith', 'F', '1966', '555-111-2222', 
    '400 oracle parkway','94065',51402, 'Redwood Shores', 
    52564, 'CA', 52790, 'Customer total', '52772');
COMMIT;

将优化器统计信息保存到磁盘:

EXEC DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO;

再次查询表统计信息:

ABLE_NAME           PARTITION_NAME       NUM_ROWS STA
-------------------- -------------------- -------- ---
CUSTOMERS                                    55500 NO 
SALES                SALES_1995                  0 NO 
SALES                SALES_1996                  0 NO 
SALES                SALES_H1_1997               0 NO 
SALES                SALES_H2_1997               0 NO 
SALES                SALES_Q1_1998           43687 YES
SALES                SALES_Q1_1999           64186 YES
SALES                SALES_Q1_2000           62197 YES
SALES                SALES_Q1_2001           60608 YES
SALES                SALES_Q1_2002               0 NO 
SALES                SALES_Q1_2003               0 NO 
SALES                SALES_Q2_1998           35758 YES
SALES                SALES_Q2_1999           54233 YES
SALES                SALES_Q2_2000           55515 YES
SALES                SALES_Q2_2001           63292 YES
SALES                SALES_Q2_2002               0 NO 
SALES                SALES_Q2_2003               0 NO 
SALES                SALES_Q3_1998           50515 YES
SALES                SALES_Q3_1999           67138 YES
SALES                SALES_Q3_2000           58950 YES
SALES                SALES_Q3_2001           65769 YES
SALES                SALES_Q3_2002               0 NO 
SALES                SALES_Q3_2003               0 NO 
SALES                SALES_Q4_1998           48874 YES
SALES                SALES_Q4_1999           62388 YES
SALES                SALES_Q4_2000           55984 YES
SALES                SALES_Q4_2001           69749 YES
SALES                SALES_Q4_2002               0 NO 
SALES                SALES_Q4_2003               0 NO 
SALES                                       918843 YES

30 rows selected. 

前面的输出显示统计数据对于客户表来说不是陈旧的,但对于销售表来说是陈旧的。

配置高频自动优化器统计收集:

EXEC DBMS_STATS.SET_GLOBAL_PREFS('AUTO_TASK_STATUS','ON');
EXEC DBMS_STATS.SET_GLOBAL_PREFS('AUTO_TASK_MAX_RUN_TIME','180');
EXEC DBMS_STATS.SET_GLOBAL_PREFS('AUTO_TASK_INTERVAL','240');

等待几分钟,然后查询数据字典:

COL OPID FORMAT 9999
COL STATUS FORMAT a11
COL ORIGIN FORMAT a20
COL COMPLETED FORMAT 99999
COL FAILED FORMAT 99999
COL TIMEOUT FORMAT 99999
COL INPROG FORMAT 99999

SELECT OPID, ORIGIN, STATUS, TO_CHAR(START_TIME, 'DD/MM HH24:MI:SS' ) AS BEGIN_TIME,
       TO_CHAR(END_TIME, 'DD/MM HH24:MI:SS') AS END_TIME, COMPLETED, FAILED,
       TIMED_OUT AS TIMEOUT, IN_PROGRESS AS INPROG
FROM  DBA_AUTO_STAT_EXECUTIONS
ORDER BY OPID;

输出显示高频作业执行了2次,标准的自动统计收集作业执行了4次:

 OPID ORIGIN               STATUS      BEGIN_TIME     END_TIME       COMPLETED FAILED TIMEOUT INPROG
----- -------------------- ----------- -------------- -------------- --------- ------ ------- ------
  487 AUTO_TASK            COMPLETED   04/06 06:43:12 04/06 06:44:38      1987      1       0      0
  548 AUTO_TASK            COMPLETED   04/06 15:45:52 04/06 15:46:21       468      1       0      0
  580 AUTO_TASK            COMPLETED   05/06 15:55:14 05/06 15:55:41       353      1       0      0
  662 AUTO_TASK            COMPLETED   05/06 19:58:08 05/06 19:58:21       145      1       0      0
  667 HIGH_FREQ_AUTO_TASK  COMPLETED   05/06 20:36:34 05/06 20:36:53       233      1       0      0
  669 HIGH_FREQ_AUTO_TASK  COMPLETED   05/06 20:40:44 05/06 20:40:48        53      1       0      0

6 rows selected. 

复位:

EXEC DBMS_STATS.SET_GLOBAL_PREFS('AUTO_TASK_STATUS','OFF');

13.3 Gathering Optimizer Statistics Manually

作为自动统计收集的替代或补充,您可以使用 DBMS_STATS 包手动收集优化器统计信息。

13.3.1 About Manual Statistics Collection with DBMS_STATS

使用 DBMS_STATS 包来操作优化器统计信息。 您可以收集各种粒度级别的对象和列的统计信息:对象、模式和数据库。 您还可以收集物理系统的统计信息。

下表总结了收集优化器统计信息的 DBMS_STATS 过程。 此软件包不收集表集群的统计信息。 但是,您可以收集表集群中各个表的统计信息。

  • GATHER_INDEX_STATS :收集索引统计信息
  • GATHER_TABLE_STATS:收集表、列和索引统计信息
  • GATHER_SCHEMA_STATS :收集模式中所有对象的统计信息
  • GATHER_DICTIONARY_STATS :收集所有系统模式的统计信息,包括 SYS 和 SYSTEM,以及其他可选模式,例如 CTXSYS 和 DRSYS
  • GATHER_DATABASE_STATS :收集数据库中所有对象的统计信息

当 OPTIONS 参数设置为 GATHER STALE 或 GATHER AUTO 时,GATHER_SCHEMA_STATS 和 GATHER_DATABASE_STATS 过程为任何具有陈旧统计信息的表和任何缺少统计信息的表收集统计信息。 如果受监视的表已修改超过 10%,则数据库会认为这些统计信息已过时并再次收集它们。

注意:如“配置自动优化器统计信息收集”中所述,您可以配置夜间作业以自动收集统计信息。

13.3.2 Guidelines for Gathering Optimizer Statistics Manually

在大多数情况下,自动统计信息收集对于以中等速度修改的数据库对象足够了。

自动收集有时可能不充分或不可用,如下所示:

  • 您执行某些类型的批量加载并且不能等待维护窗口收集统计信息,因为查询必须立即执行。
  • 在非代表性工作负载期间,自动统计信息收集会收集固定表的统计信息。
  • 自动统计信息收集不收集系统统计信息。
  • 易失性表被删除或截断,然后在当天重建。

13.3.2.1 Guideline for Setting the Sample Size

在优化器统计的上下文中,抽样是从表行的随机子集中收集统计信息。通过使数据库能够避免全表扫描和对整个表进行排序,采样可以最大限度地减少收集统计信息所需的资源。

数据库在处理表中的所有行时收集最准确的统计信息,这是一个 100% 的样本。但是,较大的样本量会增加统计数据收集操作的时间。挑战在于确定在合理时间内提供准确统计数据的样本量。

DBMS_STATS 在用户指定参数 ESTIMATE_PERCENT 时使用采样,该参数控制表中要采样的行的百分比。为了在获得必要的统计准确性的同时最大限度地提高性能,Oracle 建议 ESTIMATE_PERCENT 参数使用默认设置 DBMS_STATS.AUTO_SAMPLE_SIZE。在这种情况下,Oracle 数据库会自动选择样本大小。此设置允许使用以下内容:

  • 一种比采样快得多的基于哈希的算法
    该算法读取所有行并生成几乎与 100% 样本的统计数据一样准确的统计数据。 使用这种技术计算的统计数据是确定性的。
  • 增量统计
  • 并发统计
  • 新的直方图类型

DBA_TABLES.SAMPLE_SIZE 列指示用于收集统计信息的实际样本大小。

13.3.2.2 Guideline for Gathering Statistics in Parallel

默认情况下,数据库以表或索引级别指定的并行度收集统计信息。

您可以使用 DBMS_STATS 收集过程的 degree 参数覆盖此设置。 Oracle 建议将 degree 设置为 DBMS_STATS.AUTO_DEGREE。 此设置使数据库能够根据对象大小和与并行度相关的初始化参数的设置来选择适当的并行度。

数据库可以串行或并行收集大多数统计信息。 但是,数据库不会并行收集一些索引统计信息,包括集群索引、域索引和位图连接索引。 收集并行统计信息时,数据库可以使用抽样。

注意:不要将并行收集统计信息(一个对象)与同时收集统计信息混淆(多个对象)。

13.3.2.3 Guideline for Partitioned Objects

对于分区表和索引,DBMS_STATS 可以为每个分区收集单独的统计信息,并为整个表或索引收集全局统计信息。

同样,对于复合分区,DBMS_STATS 可以为子分区、分区和整个表或索引收集单独的统计信息。

要确定要收集的分区统计信息的类型,请为 DBMS_STATS 过程指定粒度参数。 Oracle 建议将粒度设置为默认值 AUTO 以收集子分区、分区或全局统计信息,具体取决于分区类型。 ALL 设置收集所有类型的统计信息。

13.3.2.4 Guideline for Frequently Changing Objects

当表被频繁修改时,要经常收集统计信息,以免它们过时,但不要太频繁,因为收集开销会降低性能。

您可能只需要每周或每月收集新的统计数据。 最佳实践是使用脚本或作业调度程序定期运行 DBMS_STATS.GATHER_SCHEMA_STATS 和 DBMS_STATS.GATHER_DATABASE_STATS 过程。

13.3.2.5 Guideline for External Tables

因为数据库不允许对外部表进行数据操作,所以数据库永远不会将外部表上的统计信息标记为过时。 如果外部表需要新的统计信息,例如,因为基础数据文件发生更改,则重新收集统计信息。

对于外部表,使用与内部表相同的 DBMS_STATS 过程。 请注意,DBMS_STATS.SET_TABLE_STATS 和 DBMS_STATS.GET_TABLE_STATS 的 scanrate 参数指定 Oracle 数据库扫描表中数据的速率(以 MB/s 为单位),并且仅与外部表相关。 SCAN_RATE 列出现在 DBA_TAB_STATISTICS 和 DBA_TAB_PENDING_STATS 数据字典视图中。

13.3.3 Determining When Optimizer Statistics Are Stale

表的陈旧统计信息不能准确反映其数据。 为了帮助您确定数据库对象何时需要新的统计信息,数据库提供了一个表监控工具。

监控跟踪表上 DML 操作的大致数量以及自最近一次统计信息收集以来该表是否已被截断。 要检查统计信息是否过时,请查询 DBA_TAB_STATISTICS 和 DBA_IND_STATISTICS 中的 STALE_STATS 列。 此列基于 DBA_TAB_MODIFICATIONS 视图中的数据和 DBMS_STATS 的 STALE_PERCENT 首选项。

注意:从 Oracle Database 12c 第 2 版 (12.2) 开始,您不再需要使用 DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO 来确保视图元数据是最新的。 DBA_TAB_STATISTICS、DBA_IND_STATISTICS 和 DBA_TAB_MODIFICATIONS 视图中显示的统计信息是从磁盘和内存中获取的。

STALE_STATS 列具有以下可能值:

  • YES
    统计数据是陈旧的。
  • NO
    统计数据并不过时。
  • null
    不收集统计信息。

使用 GATHER AUTO 选项执行 GATHER_SCHEMA_STATS 或 GATHER_DATABASE_STATS 只会收集没有统计信息或过时统计信息的对象的统计信息。

例如:

COL PARTITION_NAME FORMAT a15

SELECT PARTITION_NAME, STALE_STATS
FROM   DBA_TAB_STATISTICS
WHERE  TABLE_NAME = 'SALES'
AND    OWNER = 'SH'
ORDER BY PARTITION_NAME;

PARTITION_NAME  STA
--------------- ---
SALES_1995      NO 
SALES_1996      NO 
SALES_H1_1997   NO 
SALES_H2_1997   NO 
SALES_Q1_1998   YES
...

13.3.4 Gathering Schema and Table Statistics

使用 GATHER_TABLE_STATS 收集表统计信息,并使用 GATHER_SCHEMA_STATS 收集模式中所有对象的统计信息。

例如:

-- degree表示并行度
BEGIN
  DBMS_STATS.GATHER_TABLE_STATS (  
    ownname => 'sh'
,   tabname => 'customers'
,   degree  => 2  
);
END;
/

13.3.5 Gathering Statistics for Fixed Objects

固定对象是动态性能表及其索引。 这些对象记录当前的数据库活动。

与其他数据库表不同,当缺少优化器统计信息时,数据库不会自动对引用 X$ 表的 SQL 语句使用动态统计信息。 相反,优化器使用预定义的默认值。 这些默认值可能不具有代表性,并且可能导致次优的执行计划。 因此,保持固定对象统计信息是最新的很重要。

如果以前没有收集过固定对象统计信息,则 Oracle 数据库会自动收集固定对象统计信息,作为自动统计信息收集的一部分。 您还可以通过调用 DBMS_STATS.GATHER_FIXED_OBJECTS_STATS 手动收集有关固定对象的统计信息。 Oracle 建议您在数据库具有代表性活动时收集统计信息。

先决条件:您必须具有 SYSDBA 或 ANALYZE ANY DICTIONARY 系统特权才能执行此过程。

例如:

BEGIN
  DBMS_STATS.GATHER_FIXED_OBJECTS_STATS;
END;
/

13.3.6 Gathering Statistics for Volatile Tables Using Dynamic Statistics

易失性表的统计信息,即在白天被显著修改的表,很快就会过时。 例如,一个表可能被删除或截断,然后重建。

当您将 易失性对象的统计信息设置为 null 时,Oracle 数据库会在优化期间使用动态统计信息动态收集必要的统计信息。 OPTIMIZER_DYNAMIC_SAMPLING 初始化参数控制这个特性。

假设:

  • oe.orders 表非常不稳定。
  • 您想删除然后锁定订单表上的统计信息,以防止数据库收集该表上的统计信息。 通过这种方式,数据库可以动态收集必要的统计信息,作为查询优化的一部分。
  • oe 用户具有查询 DBMS_XPLAN.DISPLAY_CURSOR 的必要权限。
exec DBMS_STATS.DELETE_TABLE_STATS('OE','ORDERS');

exec DBMS_STATS.LOCK_TABLE_STATS('OE','ORDERS');

SELECT COUNT(order_id) FROM orders;
SET LINESIZE 150
SET PAGESIZE 0

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR);

--------------------------------------------------------------------------
| Id  | Operation             | Name     | Rows  | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |          |       |     2 (100)|          |
|   1 |  SORT AGGREGATE       |          |     1 |            |          |
|   2 |   INDEX FAST FULL SCAN| ORDER_PK |   105 |     2   (0)| 00:00:01 |
--------------------------------------------------------------------------
 
Note
-----
   - dynamic statistics used: dynamic sampling (level=2)

-- reset
exec DBMS_STATS.UNLOCK_TABLE_STATS('OE','ORDERS');

上述执行计划中的 Note 表明数据库对 SELECT 语句使用了动态统计信息。

13.3.7 Gathering Optimizer Statistics Concurrently

Oracle 数据库可以同时收集多个表或分区的统计信息。

13.3.7.1 About Concurrent Statistics Gathering

默认情况下,分区表的每个分区是按顺序收集的。

当启用并发统计收集模式时,数据库可以同时收集模式中多个表的优化器统计信息,或者一个表中的多个分区或子分区。 并发可以通过使数据库充分使用多个处理器来减少收集统计信息所需的总时间。

注意:并发统计收集模式不依赖于并行查询处理,但可以使用它。

13.3.7.1.1 How DBMS_STATS Gathers Statistics Concurrently

Oracle 数据库采用多种工具和技术来同时创建和管理多个统计信息收集作业。

数据库使用以下手段:

  • Oracle 调度程序
  • Oracle 数据库高级队列 (AQ)
  • Oracle 数据库资源管理器(Resource Manager)

通过使用 DBMS_STATS.SET_GLOBAL_PREF 设置 CONCURRENT 首选项来启用并发统计信息收集。

数据库运行尽可能多的并发作业。 Job Scheduler 决定并发执行多少作业以及排队执行多少作业。随着正在运行的作业完成,调度程序会出列并运行更多作业,直到数据库收集到所有表、分区和子分区的统计信息。最大作业数受 JOB_QUEUE_PROCESSES 初始化参数和可用系统资源的限制。

在大多数情况下,DBMS_STATS 过程为每个表分区或子分区创建一个单独的作业。但是,如果分区或子分区为空或非常小,那么数据库可能会自动将该对象与其他小对象批处理为单个作业,以减少作业维护的开销。

下图说明了不同级别的作业创建,其中表 3 为分区表,其他表为非分区表。作业 3 充当表 3 的协调作业,并为该表中的每个分区创建一个作业,并为表 3 的全局统计信息创建一个单独的作业。此示例假定禁用增量统计信息收集;如果启用,则数据库会在分区作业完成后从分区级别的统计信息中获取全局统计信息。

13.3.7.1.2 Concurrent Statistics Gathering and Resource Management

DBMS_STATS 包不明确管理并发统计信息收集作业使用的资源,这些作业是用户发起的统计信息收集调用的一部分。

因此,数据库可以在并发统计收集期间充分使用系统资源。 要解决这种情况,请使用资源管理器来限制并发统计收集作业所消耗的资源。 必须启用资源管理器才能同时收集统计信息。

系统提供的消费者组 ORA A U T O T A S K 注 册 所 有 统 计 信 息 收 集 作 业 。 您 可 以 为 O R A AUTOTASK 注册所有统计信息收集作业。 您可以为 ORA AUTOTASKORAAUTOTASK 创建具有适当资源分配的资源计划,以防止并发统计信息收集消耗所有可用资源。 如果您缺少自己的资源计划,并且选择不创建资源计划,请考虑使用系统提供的 DEFAULT_PLAN 激活资源管理器。

注意:ORA$AUTOTASK 消费者组与维护窗口期间自动运行的维护任务共享。 因此,当为自动统计收集激活并发时,数据库会自动管理资源,无需额外步骤。

13.3.7.2 Enabling Concurrent Statistics Gathering

要启用并发统计信息收集,请使用 DBMS_STATS.SET_GLOBAL_PREFS 过程来设置 CONCURRENT 首选项。

可能的值如下:

  • MANUAL
    仅对手动统计信息收集启用并发。
  • AUTOMATIC
    仅对自动统计信息收集启用并发。
  • ALL
    为手动和自动统计收集启用并发。
  • OFF
    手动和自动统计收集的并发性被禁用。 这是默认值。

本节中的本教程解释了如何启用并发统计信息收集。

本教程具有以下先决条件:

  • 除了收集统计数据的标准权限外,您还必须具有以下权限:
    CREATE JOB
    MANAGE SCHEDULER
    MANAGE ANY QUEUE
  • SYSAUX 表空间必须在线,因为调度程序将其内部表和视图存储在此表空间中。
  • JOB_QUEUE_PROCESSES 初始化参数必须至少设置为 4。
  • 必须启用资源管理器。
    默认情况下,资源管理器处于禁用状态。 如果您没有资源计划,请考虑使用系统提供的 DEFAULT_PLAN 启用资源管理器。

本教程假定您要执行以下操作:

  • 启用并发统计信息收集
  • 收集 sh 模式的统计信息
  • 监控 sh 统计信息的收集
ALTER SYSTEM SET RESOURCE_MANAGER_PLAN = 'DEFAULT_PLAN';
ALTER SYSTEM SET JOB_QUEUE_PROCESSES=8;

BEGIN
  DBMS_STATS.SET_GLOBAL_PREFS('CONCURRENT','ALL');
END;
/

SELECT DBMS_STATS.GET_PREFS('CONCURRENT') FROM DUAL;

DBMS_STATS.GET_PREFS('CONCURRENT')
----------------------------------
ALL

EXEC DBMS_STATS.GATHER_SCHEMA_STATS('SH');

SET LINESIZE 1000
 
COLUMN TARGET FORMAT a8
COLUMN TARGET_TYPE FORMAT a25
COLUMN JOB_NAME FORMAT a14
COLUMN START_TIME FORMAT a40
 
SELECT TARGET, TARGET_TYPE, JOB_NAME, 
       TO_CHAR(START_TIME, 'dd-mon-yyyy hh24:mi:ss')
FROM   DBA_OPTSTAT_OPERATION_TASKS 
WHERE  STATUS = 'IN PROGRESS' 
AND    OPID = (SELECT MAX(ID) 
               FROM   DBA_OPTSTAT_OPERATIONS 
               WHERE  OPERATION = 'gather_schema_stats');

TARGET                         TARGET_TYPE               JOB_NAME       TO_CHAR(START_TIME,'DD-MON-YY
------------------------------ ------------------------- -------------- -----------------------------
"SH"."SALES"                   TABLE                     ST$SD130_1_B10 05-jun-2022 22:14:33         
"SH"."SALES"."SALES_Q4_1999"   TABLE PARTITION           ST$SD130_1_B10 05-jun-2022 22:14:34     

EXEC DBMS_STATS.SET_GLOBAL_PREFS('CONCURRENT','OFF');    

13.3.7.3 Monitoring Statistics Gathering Operations

您可以使用数据字典视图监控统计数据收集作业。

以下是相关视图:

  • DBA_OPTSTAT_OPERATION_TASKS
    此视图包含作为统计信息收集操作的一部分执行或当前正在进行的任务的历史记录(记录在 DBA_OPTSTAT_OPERATIONS 中)。 每个任务代表一个在相应父操作中要处理的目标对象。
  • DBA_OPTSTAT_OPERATIONS
    此视图包含使用 DBMS_STATS 包在表、模式和数据库级别执行或当前正在进行的统计操作的历史记录。

前面视图中的 TARGET 列显示了该统计信息收集作业的目标对象,格式如下:

OWNER.TABLE_NAME.PARTITION_OR_SUBPARTITION_NAME

所有收集作业名称的统计信息都以字符串 ST$ 开头。

显示当前正在运行的统计任务和作业:

SELECT OPID, TARGET以上是关于SQL调优指南笔记13:Gathering Optimizer Statistics的主要内容,如果未能解决你的问题,请参考以下文章

SQL调优指南笔记12:Configuring Options for Optimizer Statistics Gathering

SQL调优指南笔记12:Configuring Options for Optimizer Statistics Gathering

SQL调优指南笔记22:Gathering Diagnostic Data with SQL Test Case Builder

SQL调优指南笔记9:Joins

SQL调优指南笔记9:Joins

SQL调优指南笔记1:Introduction to SQL Tuning