前言
在数据库运维中,统计信息的准确性直接影响SQL执行计划的优劣,进而决定查询性能。达梦数据库(DM8)提供了DBMS_STATS系统包来管理统计信息,本文将结合实际SQL脚本,详细介绍统计信息的收集方法与最佳实践。
DBMS_STATS包是达梦数据库用于收集、管理和查看统计信息的核心工具。统计信息包括:
1、统计信息类型和说明:
表统计信息:行数、页数、已用页数
列统计信息:不同值数量、空值数量、最大值、最小值、直方图
索引统计信息:索引层级、叶子页数、不同键值数量
2、支持的统计信息收集对象:
普通表、分区表
列存储表(HUGE表)
索引
不支持:视图、物化视图、外部表、临时表
PROCEDURE GATHER_TABLE_STATS( OWNNAME VARCHAR(128), TABNAME VARCHAR(128), PARTNAME VARCHAR(128) DEFAULT NULL, ESTIMATE_PERCENT DOUBLE DEFAULT ..., BLOCK_SAMPLE BOOLEAN DEFAULT FALSE, METHOD_OPT VARCHAR DEFAULT 'FOR ALL COLUMNS SIZE AUTO', DEGREE INT DEFAULT 1, GRANULARITY VARCHAR DEFAULT 'AUTO', CASCADE BOOLEAN DEFAULT TRUE, ... );
BEGIN
DBMS_STATS.GATHER_SCHEMA_STATS(
OWNNAME => '模式名',
ESTIMATE_PERCENT => 30,
BLOCK_SAMPLE => TRUE,
METHOD_OPT => 'FOR ALL COLUMNS SIZE AUTO',
CASCADE => TRUE
);
END;
/
-- 查看表统计信息
EXEC DBMS_STATS.TABLE_STATS_SHOW('模式名', '表名');
-- 查看列统计信息(含直方图)
EXEC DBMS_STATS.COLUMN_STATS_SHOW('模式名', '表名', '列名');
-- 查看索引统计信息
EXEC DBMS_STATS.INDEX_STATS_SHOW('模式名', '索引名');
-- 删除表统计信息
DBMS_STATS.DELETE_TABLE_STATS('模式名', '表名');
三、实战:批量收集统计信息
场景:收集指定模式下所有表的统计信息
-- 1. 查看表的最后收集时间,按数据量排序
SELECT last_analyzed "最后收集统计信息时间",
'dbms_stats.gather_table_stats('''||owner||''','''||table_name||''',null,100,TRUE,''FOR ALL COLUMNS SIZE AUTO'');' AS 收集语句,
(table_rowcount(owner,table_name)) num
FROM dba_tables
WHERE owner IN ('模式名') -- 替换为实际模式名,大写
ORDER BY num;
执行结果示例
最后收集统计信息时间 收集语句 num
2026-07-15 10:30:00 dbms_stats.gather_table_stats('SYSDBA','ORDERS',null,100,TRUE,'FOR ALL COLUMNS SIZE AUTO'); 1,500,000
2026-07-14 08:20:00 dbms_stats.gather_table_stats('SYSDBA','PRODUCTS',null,100,TRUE,'FOR ALL COLUMNS SIZE AUTO'); 500,000
NULL dbms_stats.gather_table_stats('SYSDBA','LOG_TABLE',null,100,TRUE,'FOR ALL COLUMNS SIZE AUTO'); 50,000
实际收集脚本
– 方式一:逐个收集(适合有选择性地收集)
EXEC DBMS_STATS.GATHER_TABLE_STATS('SYSDBA','ORDERS',NULL,30,TRUE,'FOR ALL COLUMNS SIZE AUTO',4);
– 方式二:整个模式收集
BEGIN
DBMS_STATS.GATHER_SCHEMA_STATS(
OWNNAME => 'SYSDBA',
ESTIMATE_PERCENT => 30,
BLOCK_SAMPLE => TRUE,
METHOD_OPT => 'FOR ALL COLUMNS SIZE AUTO',
CASCADE => TRUE,
DEGREE => 4
);
END;
/
对于超大表,全部列都收集统计信息可能开销较大,可以针对特定列进行收集:
-- 生成按列收集统计信息的语句
SELECT 'stat 100 on "'||owner||'"."'||table_name||'"("'||column_name||'");'
FROM DBA_TAB_COLUMNS
WHERE owner='用户名' AND table_name='表名';
-- 实际使用示例(对于某张5000万行的订单表,只收集关键列)
BEGIN
DBMS_STATS.GATHER_TABLE_STATS('SYSDBA','ORDERS',NULL,20,TRUE,'FOR COLUMNS ORDER_ID SIZE 100, CUSTOMER_ID SIZE 100, ORDER_DATE SIZE AUTO');
END;
/
-- 查看哪些表统计信息过时
SELECT owner, table_name, stale_stats
FROM dba_tab_statistics
WHERE stale_stats = 'YES';
文章
阅读量
获赞
