LightDB-X 24.1 支持 Oracle DBMS_STATS.GATHER_TABLE_STATS 存储过程

LightDB-X 24.1 支持 Oracle DBMS_STATS.GATHER_TABLE_STATS 存储过程

背景

LightDB-X 一直在不断提升对 Oralce 的兼容性,降低基于 Oracle 的业务系统迁移到 LightDB-X 的门槛。
在 24.1 版本中支持了 Oracle 的 DBMS_STATS.GATHER_TABLE_STATS 存储过程,提高了对 Oracle 管理功能的兼容性,本文章对该特性进行初探。

关于 LightDB-X 对 Oracle 特性的详细兼容情况,详情可查阅 orafce 插件说明

存储过程 DBMS_STATS.GATHER_TABLE_STATS

该存储过程的定义见 Oracle 官方文档 ,它的作用是收集指定表结构的统计数据,之后可通过视图 ALL_TAB_STATISTICS 视图查询表的统计数据。

LightDB-X 实现了这个存储过程的部分参数,以 LightDB-X 原生的方式收集表的统计信息,之后可通过 pg_stat_all_tables 视图或 pg_statistic 视图来找到表的统计信息,当然 LightDB-X 也支持通过 Oracle 的统计视图 ALL_TAB_STATISTIC 中查询统计信息。

目前 LightDB-X 对 DBMS_STATS.GATHER_TABLE_STATS 存储过程参数的支持情况如下:

入参 类型 必传 支持 功能
ownname VARCHAR2 schema名
tabname VARCHAR2 表名
partname VARCHAR2 分区名
estimate_percent NUMBER 统计采样率,0-100
block_sample BOOLEAN 是否使用块采样
method_opt VARCHAR2 采集方式表达式
degree NUMBER 并行度
granularity VARCHAR2 统计粒度,通常是'GLOBAL'或'ALL'
cascade BOOLEAN 是否统计索引使用情况
stattab VARCHAR2 指定自定义表存放统计信息
statid VARCHAR2 自定义统计信息的id
statown VARCHAR2 自定义表的schema
no_invalidate BOOLEAN 是否不使依赖于此统计信息的对象无效
stattype VARCHAR2 统计类型,例如:'ALL'(默认)
force BOOLEAN 是否强制执行,即使表被锁定或者有其他原因阻止统计收集
context CCONTEXT 无用
options VARCHAR2 额外收集选项

其余未标注‘支持’的选项可以传入参数,但没有任何实际作用。

该存储过程实际会映射到 ANALYZE 语句。

需要注意,partname 分区表名参数仅在 23.4 及之后版本的 LightDB-X 中创建的分区表中可以正常工作,如果是 23.3 及之前版本迁移到高版本的分区表,可能无法正常使用。

视图 ALL_TAB_STATISTICS

早在 22.2 版本中,LightDB-X 就引入了这个视图。本视图的结构与 Oracle 的 ALL_TAB_STATISTICS 视图一致,但字段的支持略有不同,因为在 LightDB-X 底层不存在一些 Oracle 的专有特性,比如 FreeList 等。

LightDB-X 也同时支持 DBA_TAB_STATISTICS 与 USER_TAB_STATISTICS 视图,它们的查询结果都是相同的。

目前对 ALL_TAB_STATISTICS 的字段支持情况:

OWNER VARCHAR2(128) 支持
TABLE_NAME VARCHAR2(128) 支持
PARTITION_NAME VARCHAR2(128) 支持
PARTITION_POSITION NUMBER 支持
SUBPARTITION_NAME VARCHAR2(128) 行为不同,lightdb 增加了分区前缀,如 P1 分区的子分区 SP1 会输出 P1_SP1
SUBPARTITION_POSITION NUMBER 支持
OBJECT_TYPE VARCHAR2(12) 支持
NUM_ROWS NUMBER 支持
BLOCKS NUMBER 支持
EMPTY_BLOCKS NUMBER NULL
AVG_SPACE NUMBER NULL
CHAIN_CNT NUMBER NULL
AVG_ROW_LEN NUMBER 支持
AVG_SPACE_FREELIST_BLOCKS NUMBER NULL
NUM_FREELIST_BLOCKS NUMBER NULL
AVG_CACHED_BLOCKS NUMBER NULL
AVG_CACHE_HIT_RATIO NUMBER NULL
IM_IMCU_COUNT NUMBER NULL
IM_BLOCK_COUNT NUMBER NULL
IM_STAT_UPDATE_TIME TIMESTAMP(9) NULL
SCAN_RATE NUMBER NULL
SAMPLE_SIZE NUMBER NULL
LAST_ANALYZED DATE 支持
GLOBAL_STATS VARCHAR2(3) NULL
USER_STATS VARCHAR2(3) NULL
STATTYPE_LOCKED VARCHAR2(5) NULL
STALE_STATS VARCHAR2(7) NULL
NOTES VARCHAR2(25) NULL
SCOPE VARCHAR2(7) 当前为固定值 SHARED

标注为 NULL 的字段不支持,仅输出 NULL。

验证

要验证 DBMS_STATS.GATHER_TABLE_STATS 与 ALL_TAB_STATISTICS 的行为,可创建普通表、分区表、子分区表来验证功能,例子如下:

create schema dbms_gather_test;
create table dbms_gather_test.dbms_stats_gather_test_1 (id int);
create table dbms_gather_test.dbms_stats_gather_test_2 (id int)
partition by range(id)
(
    PARTITION p1 VALUES LESS THAN (100),
    PARTITION p2 VALUES LESS THAN (200),
    PARTITION p3 VALUES LESS THAN (MAXVALUE)
);
create table dbms_gather_test.dbms_stats_gather_test_3 (id int, typ varchar2(10))
partition by range(id)
subpartition by list(typ)
(
    partition p1 values less than (100)
    (
        subpartition p1_sp1 values ('A', 'B'),
        subpartition p1_sp2 values ('C', 'D'),
        subpartition p1_sp3 values (default)
    ),
    partition p2 values less than (200)
    (
        subpartition p2_sp1 values ('A', 'B'),
        subpartition p2_sp2 values ('C', 'D'),
        subpartition p2_sp3 values (default)
    ),
    partition p3 values less than (maxvalue)
    (
        subpartition p3_sp1 values ('A', 'B'),
        subpartition p3_sp2 values ('C', 'D'),
        subpartition p3_sp3 values (default)
    )
);

insert into dbms_gather_test.dbms_stats_gather_test_1(id) values (1);
insert into dbms_gather_test.dbms_stats_gather_test_1(id) values (99);
insert into dbms_gather_test.dbms_stats_gather_test_1(id) values (100);
insert into dbms_gather_test.dbms_stats_gather_test_1(id) values (199);
insert into dbms_gather_test.dbms_stats_gather_test_1(id) values (200);
insert into dbms_gather_test.dbms_stats_gather_test_1(id) values (299);
insert into dbms_gather_test.dbms_stats_gather_test_1(id) values (300);

insert into dbms_gather_test.dbms_stats_gather_test_2(id) values (1);
insert into dbms_gather_test.dbms_stats_gather_test_2(id) values (99);
insert into dbms_gather_test.dbms_stats_gather_test_2(id) values (100);
insert into dbms_gather_test.dbms_stats_gather_test_2(id) values (199);
insert into dbms_gather_test.dbms_stats_gather_test_2(id) values (200);
insert into dbms_gather_test.dbms_stats_gather_test_2(id) values (299);
insert into dbms_gather_test.dbms_stats_gather_test_2(id) values (300);

insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (1, 'A');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (2, 'B');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (3, 'C');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (4, 'D');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (5, 'E');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (95, 'A');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (96, 'B');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (97, 'C');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (98, 'D');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (99, 'E');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (100, 'A');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (101, 'B');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (102, 'C');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (103, 'D');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (104, 'E');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (195, 'A');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (196, 'B');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (197, 'C');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (198, 'D');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (199, 'E');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (200, 'A');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (201, 'B');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (202, 'C');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (203, 'D');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (204, 'E');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (295, 'A');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (296, 'B');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (297, 'C');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (298, 'D');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (299, 'E');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (300, 'A');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (301, 'B');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (302, 'C');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (303, 'D');
insert into dbms_gather_test.dbms_stats_gather_test_3(id, typ) values (304, 'E');

-- drop table dbms_gather_test.dbms_stats_gather_test_1;
-- drop table dbms_gather_test.dbms_stats_gather_test_2;
-- drop table dbms_gather_test.dbms_stats_gather_test_3;

调用存储过程的示例:

begin
    DBMS_STATS.GATHER_SCHEMA_STATS(
        ownname => 'dbms_gather_test',
        tabname => 'dbms_stats_gather_test_1',
        degree => 4
    );
end;
/

begin
    DBMS_STATS.GATHER_SCHEMA_STATS(
        ownname => 'dbms_gather_test',
        tabname => 'dbms_stats_gather_test_2',
        partname => 'p1',
        degree => 4
    );
end;
/

可在调用存储过程前后,查询 PG_STATISTIC, PG_ALL_TABLE_STATS, ALL_TAB_STATISTICS 视图的差异。

select *
  from pg_statistic s
  join pg_class c on s.starelid = c.oid
 where c.relname like 'dbms_stats_gather_test%'
 order by c.relname, s.staattnum;

select * from pg_stat_all_tables where relname like 'dbms_stats_gather_test%';

SELECT *
  from dba_tab_statistics
 where table_name like 'DBMS_STATS_GATHER_TEST%';

posted on 2024-02-26 15:08  滞人  阅读(10)  评论(0编辑  收藏  举报