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%';