SQL优化——统计信息

news2024/11/26 14:54:40

文章目录

  • 1、统计信息
    • 1.1、表的统计信息
    • 1.2、列的统计信息
    • 1.3、索引的统计信息
  • 2、统计信息重要参数设置
  • 3、检查统计信息是否过期
  • 4、扩展统计信息
  • 5、动态采样
  • 6、定制统计信息收集策略

只有大表才会产生性能问题,那么怎么才能让优化器知道某个表多大呢?这就需要对表收集统计信息。基数、直方图、集群因子等概念都需要事先收集统计信息才能得到。

1、统计信息

统计信息类似于战争中的侦察兵,如果情报工作没有做好,打仗就会输掉战争。同样的道理,如果没有正确地收集表的统计信息,或者没有及时地更新表的统计信息,SQL的执行计划就会跑偏,SQL也就会出现性能问题。收集统计信息是为了让优化器选择最佳执行计划,以最少的代价(成本)查询出表中的数据。

统计信息主要分为表的统计信息、列的统计信息、索引的统计信息、系统的统计信息、数据字典的统计信息以及动态性能视图基表的统计信息。

1.1、表的统计信息

表的统计信息主要包含表的总行数(num_rows)、表的块数(blocks)以及行平均长度(avg_row_len),我们可以通过查询数据字典DBA_TABLES获取表的统计信息。

创建一个测试表T_STATS:

create table t_stats as select * from DBA_OBJECTS;

我们查看表T_STATS常用的表的统计信息:

select owner, table_name, num_rows, blocks, avg_row_len from dba_tables where owner = 'SCOTT' and table_name = 'T_STATS';

在这里插入图片描述
因为T_STATS是新创建的表,没有收集过统计信息,所以从DBA_TABLES查询数据是空的。

现在我们来收集表T_STATS的统计信息。

BEGIN
    DBMS_STATS.GATHER_TABLE_STATS(ownname => 'SCOTT',
                                  tabname => 'T_STATS',
                                  estimate_percent => 100,
                                  method_opt => 'for all columns size auto',
                                  no_invalidate => FALSE,
                                  degree => 1,
                                  cascade => TRUE);
END;

这段SQL代码是一个PL/SQL块,它调用了DBMS_STATS包中的GATHER_TABLE_STATS过程,用于收集指定表的统计信息。下面是对这段代码的详细分析:

  1. BEGIN ... END;:这是一个匿名PL/SQL块,用于执行一组SQL语句。在这个块中,你可以执行多个命令,它们作为一个整体事务来处理。

  2. DBMS_STATS.GATHER_TABLE_STATS:这是Oracle提供的一个过程,用于收集表的统计信息。统计信息对于优化器来说非常重要,因为优化器依赖这些信息来选择最佳的执行计划。

  3. ownname => 'SCOTT':这个参数指定了要收集统计信息的表的所有者(schema)名称。在这个例子中,所有者名称是SCOTT

  4. tabname => 'T_STATS':这个参数指定了要收集统计信息的表的名称。在这个例子中,表的名称是T_STATS

  5. estimate_percent => 100:这个参数指定了统计信息的收集方式。100表示使用全表扫描来收集统计信息,这将提供最准确的统计数据,但可能需要更多的时间。如果设置为DBMS_STATS.AUTO_SAMPLE_SIZE,优化器将自动决定采样的行数。

  6. method_opt => 'for all columns size auto':这个参数指定了收集统计信息的方法。for all columns表示为表中的所有列收集统计信息,size auto表示让优化器自动决定每个列的统计信息收集的粒度。

  7. no_invalidate => FALSE:这个参数指定在收集统计信息后是否使表的统计信息保持有效。FALSE表示收集统计信息后,如果表的数据发生了变化,将使统计信息无效,以便在下次查询时重新收集。

  8. degree => 1:这个参数指定了用于收集统计信息的并行度。1表示使用单线程(非并行)来收集统计信息。如果你的系统有多核处理器,增加这个值可能会加快统计信息收集的速度。

  9. cascade => TRUE:这个参数指定是否递归地收集依赖于该表的所有对象(如索引、视图、序列等)的统计信息。

总的来说,这段SQL代码的作用是为SCOTT用户下的T_STATS表收集详尽的统计信息,以便优化器可以更准确地评估查询成本并选择最佳的执行计划。通过设置estimate_percent100,确保了统计信息的准确性,同时通过cascade参数,确保了所有相关对象的统计信息也是最新的。

我们再次查看表的统计信息:

select owner, table_name, num_rows, blocks, avg_row_len from dba_tables where owner = 'SCOTT' and table_name = 'T_STATS';

在这里插入图片描述
从查询中我们可以看到,表T_STATS一共有76508行数据,1115个数据块,平均行长度为98字节。

1.2、列的统计信息

列的统计信息主要包含列的基数、列中的空值数量以及列的数据分布情况(直方图)。我们可以通过数据字典DBA_TAB_COL_STATISTICS查看列的统计信息。

现在我们查看表T_STATS常用的列统计信息:

select column_name, num_distinct, num_nulls, num_buckets, histogram
      from dba_tab_col_statistics
      where owner = 'SCOTT'
      and table_name = 'T_STATS';

在这里插入图片描述
上面查询中,第一个列表示列名字,第二个列表示列的基数,第三个列表示列中NULL值的数量,第四个列表示直方图的桶数,最后一个列表示直方图类型。

在工作中,我们经常使用下面脚本查看表和列的统计信息:

select a.column_name,
       b.num_rows,
       a.num_nulls,
       a.num_distinct                              Cardinality,
       round(a.num_distinct / b.num_rows * 100, 2) selectivity,
       a.histogram,
       a.num_buckets
from dba_tab_col_statistics a,
     dba_tables b
where a.owner = b.owner
  and a.table_name = b.table_name
  and a.owner = 'SCOTT'
  and a.table_name = 'T_STATS';

在这里插入图片描述

1.3、索引的统计信息

索引的统计信息主要包含索引blevel(索引高度-1)、叶子块的个数(leaf_blocks)以及集群因子(clustering_factor)。我们可以通过数据字典DBA_INDEXES查看索引的统计信息。

我们在OBJECT_ID列上创建一个索引:

create index idx_t_stats_id on t_stats(object_id);

创建索引的时候会自动收集索引的统计信息,运行下面脚本查看索引的统计信息:

select BLEVEL,LEAF_BLOCKS,CLUSTERING_FACTOR,STATUS from DBA_INDEXES where OWNER='SCOTT' and INDEX_NAME='IDX_T_STATS_ID';

在这里插入图片描述
如果要单独对索引收集统计信息,可以使用下面脚本收集:

BEGIN
    DBMS_STATS.GATHER_INDEX_STATS(ownname => 'SCOTT',
                                  indname => 'IDX_T_STATS_ID');
END;

2、统计信息重要参数设置

我们通常使用下面脚本收集表和索引的统计信息:

BEGIN
    DBMS_STATS.GATHER_TABLE_STATS(
            ownname => 'TAB_OWNER',
            tabname => 'TAB_NAME',
            estimate_percent => 根据表大小设置, -- 这里需要根据实际情况来设置一个具体的百分比值
            method_opt => 'for all columns size repeat',
            no_invalidate => FALSE,
            granularity      => 'AUTO',
            degree => 根据表大小,CPU资源和负载设置, -- 这里需要根据实际情况来设置一个具体的数值
            cascade => TRUE);
END;
  • ownname表示表的拥有者,不区分大小写。
  • tabname表示表名字,不区分大小写。
  • granularity表示收集统计信息的粒度,该选项只对分区表生效,默认为AUTO,表示让Oracle根据表的分区类型自己判断如何收集分区表的统计信息。对于该选项,我们一般采用AUTO方式,也就是数据库默认方式,因此,在后面的脚本中,省略该选项。
  • estimate_percent 表示采样率,范围是0.000 001~100。

我们一般对小于1GB的表进行100%采样,因为表很小,即使100%采样速度也比较快。有时候小表有可能数据分布不均衡,如果没有100%采样,可能会导致统计信息不准。因此我们建议对小表100%采样。

我们一般对表大小在1GB~5GB的表采样50%,对大于5GB的表采样30%。如果表特别大,有几十甚至上百GB,我们建议应该先对表进行分区,然后分别对每个分区收集统计信息。

一般情况下,为了确保统计信息比较准确,我们建议采样率不要低于30%。

我们可以使用下面脚本查看表的采样率:

SELECT owner,
       table_name,
       num_rows,
       sample_size,
       round(sample_size / num_rows * 100) estimate_percent
FROM DBA_TAB_STATISTICS
WHERE owner = 'SCOTT'
  AND table_name = 'T_STATS';

在这里插入图片描述
从上面查询我们可以看到,对表T_STATS是100%采样的。现在我们将采样率设置为30%。

BEGIN
    DBMS_STATS.GATHER_TABLE_STATS(ownname => 'SCOTT',
                                  tabname => 'T_STATS',
                                  estimate_percent => 30,
                                  method_opt => 'for all columns size auto',
                                  no_invalidate => FALSE,
                                  degree => 1,
                                  cascade => TRUE);
END;

再看表的采样率:

SELECT owner,
       table_name,
       num_rows,
       sample_size,
       round(sample_size / num_rows * 100) estimate_percent
FROM DBA_TAB_STATISTICS
WHERE owner = 'SCOTT'
  AND table_name = 'T_STATS';

在这里插入图片描述
从上面查询我们可以看到采样率为30%,表的总行数被估算为76890,而实际上表的总行数为76508。设置采样率30%的时候,一共分析了23076条数据,表的总行数等于round(23076*100/30),也就是76890。

除非一个表是小表,否则没有必要对一个表100%采样。因为表一直都会进行DML操作,表中的数据始终是变化的。

method_opt 用于控制收集直方图策略。

method_opt => 'for all columns size 1’表示所有列都不收集直方图,如下所示:

BEGIN
    DBMS_STATS.GATHER_TABLE_STATS(ownname => 'SCOTT',
                                  tabname => 'T_STATS',
                                  estimate_percent => 100,
                                  method_opt => 'for all columns size 1',
                                  no_invalidate => FALSE,
                                  degree => 1,
                                  cascade => TRUE);
END;

我们查看直方图信息:

select a.column_name,
       b.num_rows,
       a.num_nulls,
       a.num_distinct                              Cardinality,
       round(a.num_distinct / b.num_rows * 100, 2) selectivity,
       a.histogram,
       a.num_buckets
from dba_tab_col_statistics a,
     dba_tables b
where a.owner = b.owner
  and a.table_name = b.table_name
  and a.owner = 'SCOTT'
  and a.table_name = 'T_STATS';

在这里插入图片描述
从上面查询我们看到,所有列都没有收集直方图。

method_opt => 'for all columns size skewonly’表示对表中所有列收集自动判断是否收集直方图,如下所示:

BEGIN
    DBMS_STATS.GATHER_TABLE_STATS(ownname => 'SCOTT',
                                  tabname => 'T_STATS',
                                  estimate_percent => 100,
                                  method_opt => 'for all columns size skewonly',
                                  no_invalidate => FALSE,
                                  degree => 1,
                                  cascade => TRUE);
END;

我们查看直方图信息,如下所示:

select a.column_name,
       b.num_rows,
       a.num_nulls,
       a.num_distinct                              Cardinality,
       round(a.num_distinct / b.num_rows * 100, 2) selectivity,
       a.histogram,
       a.num_buckets
from dba_tab_col_statistics a,
     dba_tables b
where a.owner = b.owner
  and a.table_name = b.table_name
  and a.owner = 'SCOTT'
  and a.table_name = 'T_STATS';

在这里插入图片描述
从上面查询我们可以看到,除了OBJECT_ID列和EDITION_NAME列,其余所有列都收集了直方图。因为EDITION_NAME列全是NULL,所以没必要收集直方图。OBJECT_ID列选择性为100%,没必要收集直方图。

在实际工作中千万不要使用method_opt => ‘for all columns size skewonly’ 收集直方图信息,因为并不是表中所有的列都会出现在where条件中,对没有出现在where条件中的列收集直方图没有意义。

method_opt => 'for all columns size auto’表示对出现在where条件中的列自动判断是否收集直方图。

现在我们删除表中所有列的直方图:

BEGIN
    DBMS_STATS.GATHER_TABLE_STATS(ownname => 'SCOTT',
                                  tabname => 'T_STATS',
                                  estimate_percent => 100,
                                  method_opt => 'for all columns size 1',
                                  no_invalidate => FALSE,
                                  degree => 1,
                                  cascade => TRUE);
END;

我们执行下面SQL,以便将owner列放入where条件中:

select count(*) from t_stats where owner='SYS';

接下来我们刷新数据库监控信息:

begin
    dbms_stats.flush_database_monitoring_info;
end;

我们使用method_opt => 'for all columns size auto’方式对表收集统计信息:

BEGIN
    DBMS_STATS.GATHER_TABLE_STATS(ownname => 'SCOTT',
                                  tabname => 'T_STATS',
                                  estimate_percent => 100,
                                  method_opt => 'for all columns size auto',
                                  no_invalidate => FALSE,
                                  degree => 1,
                                  cascade => TRUE);
END;

然后我们查看直方图信息:

select a.column_name,
       b.num_rows,
       a.num_nulls,
       a.num_distinct                              Cardinality,
       round(a.num_distinct / b.num_rows * 100, 2) selectivity,
       a.histogram,
       a.num_buckets
from dba_tab_col_statistics a,
     dba_tables b
where a.owner = b.owner
  and a.table_name = b.table_name
  and a.owner = 'SCOTT'
  and a.table_name = 'T_STATS';

在这里插入图片描述
从上面查询我们可以看到,Oracle自动地对owner列收集了直方图。

思考,如果将选择性比较高的列放入where条件中,会不会自动收集直方图?现在我们将OBJECT_NAME列放入where条件中:

select count(*) from t_stats where object_name='EMP';

然后我们刷新数据库监控信息:

begin
    dbms_stats.flush_database_monitoring_info;
end;

我们收集统计信息:

SQL> BEGIN
  2    DBMS_STATS.GATHER_TABLE_STATS(ownname          => 'SCOTT',
  3                                  tabname          => 'T_STATS',
  4                                  estimate_percent => 100,
  5                                  method_opt       => 'for all columns size auto',
  6                                  no_invalidate    => FALSE,
  7                                  degree           => 1,
  8                                  cascade          => TRUE);
  9  END;
 10  /

PL/SQL procedure successfully completed.

我们查看OBJECT_NAME列是否收集了直方图:

select a.column_name,
       b.num_rows,
       a.num_nulls,
       a.num_distinct                              Cardinality,
       round(a.num_distinct / b.num_rows * 100, 2) selectivity,
       a.histogram,
       a.num_buckets
from dba_tab_col_statistics a,
     dba_tables b
where a.owner = b.owner
  and a.table_name = b.table_name
  and a.owner = 'SCOTT'
  and a.table_name = 'T_STATS';

在这里插入图片描述
从上面查询我们可以看到,OBJECT_NAME列没有收集直方图。由此可见,使用AUTO方式收集直方图很智能。mothod_opt默认的参数就是 for all columns size auto。

method_opt => 'for all columns size repeat’表示当前有哪些列收集了直方图,现在就对哪些列收集直方图。

当前只对OWNER列收集了直方图,现在我们使用REPEAT方式收集直方图:

BEGIN
    DBMS_STATS.GATHER_TABLE_STATS(ownname => 'SCOTT',
                                  tabname => 'T_STATS',
                                  estimate_percent => 100,
                                  method_opt => 'for all columns size repeat',
                                  no_invalidate => FALSE,
                                  degree => 1,
                                  cascade => TRUE);
END;

查看直方图信息:
在这里插入图片描述
从查询中我们可以看到,使用REPEAT方式延续了上次收集直方图的策略。对一个运行稳定的系统,我们应该采用REPEAT方式收集直方图。

method_opt => 'for columns object_type size skewonly’表示单独对OBJECT_TYPE列收集直方图,对于其余列,如果之前收集过直方图,现在也收集直方图。

在实际工作中,我们需要对列收集直方图就收集直方图,需要删除某列直方图就删除其直方图,当系统趋于稳定之后,使用REPEAT方式收集直方图。

no_invalidate表示共享池中涉及到该表的游标是否立即失效,默认值为DBMS_STATS. AUTO_INVALIDATE,表示让Oracle自己决定是否立即失效。我们建议将no_invalidate参数设置为FALSE,立即失效。因为我们发现有时候SQL执行缓慢是因为统计信息过期导致,重新收集了统计信息之后执行计划还是没有更改,原因就在于没有将这个参数设置为false。

degree表示收集统计信息的并行度,默认为NULL。如果表没有设置degree,收集统计信息的时候后就不开并行;如果表设置了degree,收集统计信息的时候就按照表的degree来开并行。可以查询DBA_TABLES.degree来查看表的degree,一般情况下,表的degree都为1。我们建议可以根据当时系统的负载、系统中CPU的个数以及表大小来综合判断设置并行度。

cascade表示在收集表的统计信息的时候,是否级联收集索引的统计信息,默认值为DBMS_STATS.AUTO_CASCADE,表示让Oracle自己判断是否级联收集索引的统计信息。我们一般将其设置为TRUE,在收集表的统计信息的时候,级联收集索引的统计信息。

3、检查统计信息是否过期

收集完表的统计信息之后,如果表中有大量数据发生变化,这时表的统计信息就过期了,我们需要重新收集表的统计信息,如果不重新收集,可能会导致执行计划走偏。

现在我们更新表中的数据,将object_id<=10000的owner更新为’SCOTT’:

update t_stats set owner='SCOTT' where object_id<=10000;

然后使用下面方法检查表统计信息是否过期,先刷新数据库监控信息:

begin
    dbms_stats.flush_database_monitoring_info;
end;

然后我们执行下面查询:

select owner, table_name, object_type, stale_stats, last_analyzed
from dba_tab_statistics
where owner = 'SCOTT'
  and table_name = 'T_STATS';

在这里插入图片描述
STALE_STATS显示为YES表示表的统计信息过期了。如果STALE_STATS显示为NO,表示表的统计信息没有过期。

我们可以通过下面查询找出统计信息过期的原因:

select table_owner, table_name, inserts, updates, deletes, timestamp
from all_tab_modifications
where table_owner = 'SCOTT'
  and table_name = 'T_STATS';

在这里插入图片描述
从查询结果我们可以看到,从上一次收集统计信息到现在,表被更新了19418行数据,所以表的统计信息过期了。

现在我们重新收集表的统计信息:

BEGIN
    DBMS_STATS.GATHER_TABLE_STATS(ownname => 'SCOTT',
                                  tabname => 'T_STATS',
                                  estimate_percent => 100,
                                  method_opt => 'for columns owner size skewonly',
                                  no_invalidate => FALSE,
                                  degree => 1,
                                  cascade => TRUE);
END;

我们再次查看SQL的执行计划:

EXPLAIN PLAN for  select * from t_stats where OWNER='SCOTT';

SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY);

在这里插入图片描述
重新收集完统计信息之后,优化器估算返回9 718行数据,这次SQL没走索引扫描而是走的全表扫描,SQL走了正确的执行计划。

细心的你可能会认为走索引扫描的性能高于全表扫描,因为索引扫描逻辑读为1 502,而全表扫描逻辑读为1 690,所以索引扫描性能高。其实这是不对的,衡量一个SQL的性能不能只看逻辑读,还要结合SQL的物理I/O次数综合判断。

Oracle是怎么判断一个表的统计信息过期了呢?当表中有超过10%的数据发生变化(INSERT,UPDATE,DELETE),就会引起统计信息过期。

在进行SQL优化的时候,我们需要检查表的统计信息是否过期,如果表的统计信息过期了,要及时更新表的统计信息。

数据字典all_tab_modifications还可以用来判断哪些表需要定期降低高水位,比如一个表经常进行insert、delete,那么这个表应该定期降低高水位,这个表的索引也应该定期重建。除此之外,all_tab_modifications还可以用来判断系统中哪些表是业务核心表、表的数据每天增长量等。

4、扩展统计信息

当where条件中有多个谓词过滤条件,但是这些谓词过滤条件彼此是有关系的而不是相互独立的,这时我们可能需要收集扩展统计信息以便优化器能够估算出较为准确的行数(Rows)。

我们创建一个表T:

create table t as
select level as id, level || 'a' as a, level || level || 'b' as b
from dual
connect by level < 100;

查询一下这这张表:

select * from T;

在这里插入图片描述
在T表中,知道A列的值就知道B列的值,A和B这样的列就叫作相关列。

需要注意的是,扩展统计信息只能用于等值查询,不能用于非等值查询。

5、动态采样

如果一个表从来没收集过统计信息,默认情况下Oracle会对表进行动态采样(Level=2)以便优化器估算出较为准确的Rows,动态采样的最终目的就是为了让优化器能够评估出较为准确的Rows

动态采样的级别分为11级:

  • level 0:不启用动态采样。
  • level 1:当表(非分区表)没有收集过统计信息并且这个表要与另外的表进行关联(不能是单表访问),同时该表没有索引,表的数据块必须大于32个,满足这些条件的时候,Oracle会随机扫描表中32个数据块,然后评估返回的Rows。
  • level 2:对没有收集过统计信息的表启用动态采样,采样的块数为64个,如果表的块数小于64个,表有多少个块就会采样多少个块。
  • level 3:对没有收集过统计信息的表启用动态采样,采样的块数为64个。如果表已经收集过统计信息,但是优化器不能准确地估算出返回的Rows,而是靠猜,比如WHERE SUBSTR(owner,1,3),这时会随机扫描64个数据块进行采样。
  • level 4:对没有收集过统计信息的表启用动态采样,采样的块数为64个。如果表已经收集过统计信息,但是表有两个或者两个以上过滤条件(AND/OR),这时会随机扫描64个数据块进行采样,相关列问题就必须启用至少level 4进行动态采样。level4采样包含了level 3的采样数据。
  • level 5:收集满足level 4采样条件的数据,采样的块数为128个。
  • level 6:收集满足level 4采样条件的数据,采样的块数为256个。
  • level 7:收集满足level 4采样条件的数据,采样的块数为512个。
  • level 8:收集满足level 4采样条件的数据,采样的块数为1 024个。
  • level 9:收集满足level 4采样条件的数据,采样的块数为4 086个。
  • level 10:收集满足level 4采样条件的数据,采样表中所有的数据块。
  • level 11:Oracle自动判断如何采样,采样的块数由Oracle自动决定。

什么时候需要启用动态采样呢?
当系统中有全局临时表,就需要使用动态采样,因为全局临时表无法收集统计信息,我们建议对全局临时表至少启用level 4进行采样。

当执行计划中表的Rows估算有严重偏差的时候,例如相关列问题,或者两表关联有多个连接列,关联之后Rows算少,或者是where过滤条件中对列使用了substr、instr、like,又或者是where过滤条件中有非等值过滤,或者group by之后导致Rows估算错误,此时我们可以考虑使用动态采样,同样,我们建议动态采样至少设置为level 4。

在数据仓库系统中,有些报表SQL是采用Obiee/SAP BO/Congnos自动生成的,此类SQL一般都有几十行甚至几百行,SQL的过滤条件一般也比较复杂,有大量的AND和OR过滤条件,同时也可能有大量的where子查询过滤条件,SQL最终返回的数据量其实并不多。对于此类SQL,如果SQL执行缓慢,有可能是因为SQL的过滤条件太复杂,从而导致优化器不能估算出较为准确的Rows而产生了错误的执行计划。我们可以考虑启用动态采样level 6观察性能是否有所改善,我们曾利用该方法优化了大量的报表SQL。

最后,需要注意的是,不要在系统级更改动态采样级别,默认为2就行,如果某个表需要启用动态采样,直接在SQL语句中添加HINT即可。

6、定制统计信息收集策略

优化器在计算执行计划的成本时依赖于统计信息,如果没有收集统计信息,或者是统计信息过期了,那么优化器就会出现严重偏差,从而导致性能问题。因此要确保统计信息准确性。虽然数据库自带有JOB每天晚上会定时收集数据库中所有表的统计信息,但是如果数据库特别大,自带的JOB无法完成全库统计信息收集。一些资深的DBA会关闭数据库自带的统计信息收集JOB,根据实际情况自己定制收集统计信息策略。

下面脚本用于收集SCOTT账户下统计信息过期了或者是从没收集过统计信息的表的统计信息,采样率也根据表的段大小做出了相应调整。

declare
    cursor stale_table is
        select owner,
               segment_name,
               case
                   when segment_size < 1 then
                       100
                   when segment_size >= 1 and segment_size <= 5 then
                       50
                   when segment_size > 5 then
                       30
                   end as percent,
               6       as degree
        from (select owner,
                     segment_name,
                     sum(bytes / 1024 / 1024 / 1024) segment_size
              from DBA_SEGMENTS
              where owner = 'SCOTT'
                and segment_name in
                    (select table_name
                     from DBA_TAB_STATISTICS
                     where (last_analyzed is null or stale_stats = 'YES')
                       and owner = 'SCOTT')
              group by owner, segment_name);
begin
    dbms_stats.flush_database_monitoring_info;
    for stale in stale_table
        loop
            dbms_stats.gather_table_stats(ownname => stale.owner,
                                          tabname => stale.segment_name,
                                          estimate_percent => stale.percent,
                                          method_opt => 'for all columns size repeat',
                                          degree => stale.degree,
                                          cascade => true);
        end loop;
end;

在实际工作中,我们可以根据自身数据库中实际情况,对以上脚本进行修改。

全局临时表无法收集统计信息,我们可以抓出系统中的全局临时表,抓出系统中使用到全局临时表的SQL,然后根据实际情况,对全局临时表进行动态采样,或者是人工对全局临时表设置统计信息(DBMS_STATS.SET_TABLE_STATS)。

下面脚本抓出系统中使用到全局临时表的SQL:

select b.object_owner, b.object_name, a.temporary, sql_text
  from dba_tables a, v$sql_plan b, v$sql c
 where a.owner = b.object_owner
   and a.temporary = 'Y'
   and a.table_name = b.object_name
   and b.sql_id = c.sql_id;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1604329.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

果园系统养殖游戏喂养偷菜种植浇水养成小程序

装扮 通过购买装扮场景切换不同的农场风格 土地升级 通过特定的材料对土地和房屋进行升级 日志 记录道具的使用数量及金币农作物的收入情况 幸运转盘 可用金币进行抽奖 宝箱开启 获得宝箱后可以通过金币开启 每日签到 每日签到获得奖励 系统公告 可以第一时间知道游戏的更新和…

Linux进阶--文本处理grep、sed、awk命令

目录 一、grep &#xff08;1&#xff09;用文件查找 二、正则表达式 三、sed命令 四、awk命令 grep、sed、awk可以称作linux里的三驾马车 一、grep grep&#xff1a;一种强大的文本搜索工具&#xff0c;它能使用正则表达式匹配模式搜 索文本&#xff0c;并把匹配的行打…

智能电视/盒子长文字输入困难?手把手教您解决这个难题!(电视盒子跨屏输入/打字,亲测有效!)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 解决方案 📒📝 方法一📝 方法二🎈 获取方式 🎈⚓️ 相关链接 ⚓️📖 介绍 📖 在使用智能电视/电视盒子的时候,会遇到这样一个场景:需要输入一个很长的网址,或者是想要粘贴一段很长的文字。如何使用遥控器要完成…

【C语言】qsort()函数排序及其模拟实现,万物皆可排!

&#x1f525;博客主页&#x1f525;&#xff1a;【 坊钰_CSDN博客 】 欢迎各位点赞&#x1f44d;评论✍收藏⭐ 目录 1. 函数介绍 2. qsort举例排列整型变量 3. qsort举例排列结构型变量 3.1 按名字排序 3.1.1 srtcmp函数 3.2 按年龄排序 4. qsort函数模拟实现(采用冒泡的…

python怎么连接oracle

一&#xff1a;弄清版本&#xff0c;最重要&#xff01;&#xff01;&#xff01; 首先安装配置时&#xff0c;必须把握一个点&#xff0c;就是版本一致&#xff01;包括&#xff1a;系统版本&#xff0c;python版本&#xff0c;oracle客户端的版本&#xff0c;cx_Oracle的版本…

工作流 jbpm概述

文章目录 1 工作流概述2 jBPM概述3 jBPM开发环境搭建及其配置3.1 准备工作3.2 搭建jBPM开发环境3.3 加入jar包 总结 1 工作流概述 工作流&#xff08;Workflow&#xff09;&#xff0c;就是“业务过程的部分或整体在计算机应用环境下的自动化”&#xff0c;它主要解决的是“使…

STM32 CAN过滤器细节

STM32 CAN过滤器细节 简介 每组筛选器包含2个32位的寄存器&#xff0c;分别为CAN_FxR1和CAN_FxR2&#xff0c;它们用来存储要筛选的ID或掩码 四种模式 模式说明32位掩码模式CAN_FxR1存储ID&#xff0c; CAN_FxR2存储哪个位必须要与CAN_FxR1中的ID一致 &#xff0c; 2个寄存器…

Linux网络配置和操作命令

网络配置命令 Linux系统中最常用的网络配置命令包括 ifconfig route 其中 ifconfig 用来查看和配置网络接口 通常是网卡 信息 包括网络接口设备的 IP 地址 掩码等 route 用来管理 Linux系统内核中的路由表 它最大的用途就是用来设定静态的路由表项 通常是在系统用 ifconfig 配…

内置管线升级到SBP,如何复用之前打包的AssetBundle

1&#xff09;内置管线升级到SBP&#xff0c;如何复用之前打包的AssetBundle 2&#xff09;安卓真机&#xff0c;在Unity 2021.3.31版本下Buffer数据异常 3&#xff09;URP里CullResults.CreateSharedRendererScene下面的消耗 4&#xff09;移动端是否支持曲面细分着色 这是第3…

Element——组件

element官网 https://element.eleme.cn/#/zh-CN/component/layout vscode格式化快捷键&#xff1a;shiftaltf table表格 <template><el-table:data"tableData"style"width: 100%"><el-table-columnprop"date"label"日期…

idea在controller或者service使用ctrl+alt+b进入方法后,如何返回到 进入前的那一层

idea在controller或者service使用ctrlaltb进入方法后&#xff0c;如何返回到进入方法的最外层 解决方案使用 ctrlalt ← /→← /→ 键盘上的左右键盘

Linux 搭建私有yum源仓库

一、环境准备 IP系统版本作用192.168.140.155CentOS 7.9.2009yum源仓库192.168.140.153CentOS 7.9.2009测试 准备两台服务器&#xff0c;一台作为yum源仓库&#xff0c;另一台作为测试使用。 二、搭建yum源服务器 &#xff08;无法连接外网的情况&#xff0c;需要去官网下载镜…

MobX入门指南:快速上手状态管理库

一、什么是MobX MobX 是一个状态管理库&#xff0c;它可以让你轻松地管理应用程序的状态&#xff0c;并且可以扩展和维护。它使用观察者模式来自动传播你的状态的变化到你的 React 组件。 二、安装及配置 安装 MobX 和 MobX-React&#xff1a;你可以使用 npm 或 yarn 安装这…

MDK stm32怎么生成bin文件

第一种 D:\Keil_v5\ARM\ac5.6\bin\fromelf.exe --bin -o ../../Output/atk_f407.bin ../../Output/atk_f407.axf 空格解析 D:\Keil_v5\ARM\ac5.6\bin\fromelf.exe一个空格--bin一个空格-o两个空格../../Output/atk_f407.bin ../../Output/atk_f407.axf &#xff08;注意后…

Python零基础从小白打怪升级中~~~~~~~多线程

线程安全和锁 一、全局解释器锁 首先需要明确的一点是GIL并不是Python的特性&#xff0c;它是在实现Python解析器(CPython)时所引入的一个概念。 GIL全称global interpreter lock&#xff0c;全局解释器锁。 每个线程在执行的时候都需要先获取GIL&#xff0c;保证同一时刻只…

爬虫 | 网易新闻热点数据的获取与保存

Hi&#xff0c;大家好&#xff0c;我是半亩花海。本项目是一个简单的网络爬虫&#xff0c;用于从网易新闻的热点新闻列表中提取标题和对应的链接&#xff0c;并将提取到的数据保存到一个 CSV 文件中。 目录 一、技术栈 二、功能说明 三、注意事项 四、代码解析 1. 导入所需…

html+vue编写分页功能

效果&#xff1a; html关键代码&#xff1a; <div class"ui-jqgrid-resize-mark" id"rs_mlist_table_C87E35BE"> </div><div class"list_component_pager ui-jqgrid-pager undefined" dir"ltr"><div id"pg…

MySQL(2024.4.17)

目录 1. 什么是MySQL的MVCC机制&#xff1f; 2. 如何理解InnoDB的Next-Key Lock机制&#xff1f; 3. 快照读和当前读的区别&#xff1f; 4. 如何在SQL语句中触发当前读&#xff1f; 5. MySQL默认的隔离级别是什么&#xff1f; 6. 如何避免在使用当前读时可能出现的死锁问…

【LLM】认识LLM

文章目录 1.LLM1.1 LLM简介1.2 LLM发展1.3 市面常见的LLM1.4 LLM涌现的能力 2.RAG2.1 RAG简介2.2 RAG 的工作流程2.3 RAG 和 Finetune 对比2.4 RAG的使用场景分析 3. LangChain3.1 LangChain简介3.2 LangChain的核心组件3.3 LangChain 入门 4.开发 RAG 应用的整体流程5. 环境配…

虚幻引擎源码版安装下载,点击GenerateProjectFiles.bat报错 error NU1101NuGet包问题解决参考方案

开发环境配置与源码安装使用 安装VS2022 按照官方文档安装需要的vs配置 虚幻引擎源代码下载 Epic里面下载的引擎与源代码引擎区别&#xff1a;Epic里面下载的引擎是已经编译过的它的源代码访问权限不完整&#xff0c;源代码版本提供比较完整引擎代码&#xff0c;并且可以修…