KingbaseES 统计信息深度调优:从自动收集到扩展统计,精准提升计划质量

前言

在 KingbaseES 数据库里,SQL 执行计划好不好,直接决定了查询速度快不快!优化器能选出最优计划,全靠统计信息这个"关键依据"------要是统计信息缺了、过时了或者不准,优化器就跟"瞎猜"没啥区别,要么选错扫描方式,要么估错结果集大小,最后导致 SQL 执行效率拉胯。今天咱就从统计信息的基础逻辑唠起,拆解自动收集、主动收集、扩展统计这些核心调优手段,再配上实打实的实战代码,帮你把统计信息质量拿捏得死死的,让优化器每次都能选对执行计划!

文章目录

  • 前言
    • 一、统计信息到底是什么?优化器的"决策说明书"
      • [1.1 统计信息的核心内容](#1.1 统计信息的核心内容)
      • [1.2 为什么统计信息会影响性能?举个真实例子](#1.2 为什么统计信息会影响性能?举个真实例子)
    • 二、自动收集:让数据库"主动"维护统计信息
      • [2.1 核心配置参数(kingbase.conf)](#2.1 核心配置参数(kingbase.conf))
      • [2.2 自动收集的适用场景与注意事项](#2.2 自动收集的适用场景与注意事项)
      • [2.3 查看自动收集状态(实战代码)](#2.3 查看自动收集状态(实战代码))
    • 三、主动收集:手动掌控统计信息更新时机
      • [3.1 主动收集的常用场景](#3.1 主动收集的常用场景)
      • [3.2 实战代码:主动收集统计信息](#3.2 实战代码:主动收集统计信息)
        • [1. 全库收集(大库慎⽤,耗时久)](#1. 全库收集(大库慎⽤,耗时久))
        • [2. 单表/指定列收集(推荐,影响范围小)](#2. 单表/指定列收集(推荐,影响范围小))
        • [3. 带采样率的收集(大表提速关键)](#3. 带采样率的收集(大表提速关键))
        • [4. 收集后验证统计信息准确性](#4. 收集后验证统计信息准确性)
    • 四、扩展统计信息:解决多列相关性的"痛点"
      • [4.1 扩展统计的三种类型](#4.1 扩展统计的三种类型)
      • [4.2 实战代码:创建与使用扩展统计](#4.2 实战代码:创建与使用扩展统计)
        • [1. 场景准备:存在函数依赖的表](#1. 场景准备:存在函数依赖的表)
        • [2. 创建函数依赖扩展统计](#2. 创建函数依赖扩展统计)
        • [3. 创建多元 N-Distinct 统计(优化 group by 场景)](#3. 创建多元 N-Distinct 统计(优化 group by 场景))
        • [4. 创建多元 MCV 统计(优化多列条件查询)](#4. 创建多元 MCV 统计(优化多列条件查询))
        • [5. 管理扩展统计对象](#5. 管理扩展统计对象)
    • 五、统计信息调优避坑指南:这些错误别踩!
      • [5.1 大表采样偏差导致统计不准](#5.1 大表采样偏差导致统计不准)
      • [5.2 长期不更新统计信息](#5.2 长期不更新统计信息)
      • [5.3 忽略多列查询的扩展统计](#5.3 忽略多列查询的扩展统计)
      • [5.4 创建索引后未更新统计信息](#5.4 创建索引后未更新统计信息)
    • 六、统计信息调优流程:从排查到优化的完整步骤
    • 总结

一、统计信息到底是什么?优化器的"决策说明书"

简单说,统计信息就是数据库给表、列、索引做的"数据概况总结"------比如表有多少行、列里哪些值出现得频繁、值的分布情况咋样。优化器拿着这些信息,就能算出来查询要扫多少数据、耗多少 IO 和 CPU,进而挑出最省时间的执行计划。

1.1 统计信息的核心内容

  • 表级信息 :表占了多少磁盘空间、总共有多少行数据,这些都存在 sys_class 系统表里。
  • 列级信息 :既有 NULL 值占比、列的平均宽度、唯一值数量这些基础信息,也有高频值、直方图、相关系数这些数据分布信息,全存在 sys_statistic 系统表里。
  • 扩展统计信息 :专门解决多列之间的关联问题------比如 a 列和 b 列始终相等,单列统计看不出来,就得靠扩展统计来补位。

1.2 为什么统计信息会影响性能?举个真实例子

假设有张 10000 行的 student 表,sno 是 1~10000 递增的主键。要是统计信息没及时更,查 sno > 2 时:

  • 优化器可能瞎估,以为只返回 3333 行,选了 Bitmap 索引扫描;
  • 但实际要返回 9998 行(几乎是全表数据),这时候全表扫描比索引扫描快多了;
  • 只要更一下统计信息,优化器立马选全表扫描,执行时间直接从秒级降到毫秒级,差距贼明显!

二、自动收集:让数据库"主动"维护统计信息

KingbaseES 默认就开着 autovacuum 这个后台进程,跟个"巡检员"似的,自动盯着表的数据变动。等变动到一定阈值,就会触发 ANALYZE 操作更统计信息,根本不用咱手动操心。

2.1 核心配置参数(kingbase.conf)

自动收集的规矩能靠参数改,按自己的业务场景调就行:

sql 复制代码
-- 总开关:是否启用自动收集(默认开着)
autovacuum = on

-- 自动 ANALYZE 触发条件:表变动行数 >= 50 + 表总行数*10%
autovacuum_analyze_threshold = 50
autovacuum_analyze_scale_factor = 0.1

-- 最多能同时跑几个自动收集进程(默认 3 个)
autovacuum_max_workers = 3

-- 多久检查一次数据库变动(默认 1 分钟)
autovacuum_naptime = 1min

-- 执行时间超过 100ms 的自动收集操作记日志(方便排查问题)
log_autovacuum_min_duration = 100ms

2.2 自动收集的适用场景与注意事项

  • 适合:日常业务里数据变动比较平缓的表,比如电商的用户表、订单表,不用咋管就能自动维护好。
  • 要注意:
    1. 大表批量导入、更新后,自动收集反应会慢半拍,统计信息会暂时不准;
    2. 大表要是还按默认的 10% 阈值来,可能频繁触发收集,占系统资源,拖业务后腿。

2.3 查看自动收集状态(实战代码)

sql 复制代码
-- 查 student 表的自动收集情况,一眼看清啥时候更过
select 
  relname as 表名,
  last_vacuum as 最后一次vacuum时间,
  last_analyze as 最后一次analyze时间,
  n_dead_tup as 死亡元组数,
  n_live_tup as 存活元组数
from sys_stat_user_tables 
where relname = 'student';

-- 查当前正在跑的自动收集进程,看看有没有卡壳
select * from sys_stat_activity where usename = 'autovacuum';

-- 查自动收集的历史日志,确认是不是正常触发了
select * from sys_log where message like '%autovacuum%analyze%' order by log_time desc limit 10;

三、主动收集:手动掌控统计信息更新时机

自动收集虽然省心,但有些场景下必须手动触发 ANALYZE,才能保证统计信息实时准确,不然优化器还得瞎决策。

3.1 主动收集的常用场景

  1. 批量插入/更新/删除大量数据后(比如一次性导 100 万行,自动收集赶不上);
  2. 创建索引后(索引的统计信息得手动更,优化器才知道它有用);
  3. 执行计划预估不准时(比如实际返回 1000 行,优化器估成 10 行,明显不对)。

3.2 实战代码:主动收集统计信息

1. 全库收集(大库慎⽤,耗时久)
sql 复制代码
-- 收集所有表的统计信息(大库千万别随便用,容易阻塞业务,尽量避高峰)
ANALYZE;
2. 单表/指定列收集(推荐,影响范围小)
sql 复制代码
-- 收集 student 表所有列的统计信息,针对性强
ANALYZE student;

-- 只收集 student 表的 sno、sname 列,效率更高,不浪费资源
ANALYZE student(sno, sname);

-- 收集完查一下,确认是不是真生效了
select relname, last_analyze from sys_stat_user_tables where relname = 'student';
3. 带采样率的收集(大表提速关键)

大表全量收集太费时间,指定采样率就很香,能平衡效率和准确性(默认采样 30000 行):

sql 复制代码
-- 采样 10% 的页面收集 student 表统计信息(大表优先选这个)
ANALYZE student TABLESAMPLE SYSTEM (10);

-- 数据分布不均匀时,用随机采样更精准,不会漏关键数据
ANALYZE student TABLESAMPLE BERNOULLI (10);

-- 小表或数据分布极不均匀时,直接全量收集,一步到位
ANALYZE student TABLESAMPLE SYSTEM (100);
4. 收集后验证统计信息准确性
sql 复制代码
-- 查 table级统计信息,看看预估行数准不准
select 
  relname as 表名,
  reltuples as 预估行数,
  relpages as 页面数,
  current_timestamp - last_analyze as 距上次更新时间
from sys_class 
join sys_stat_user_tables on relname = relname
where relname = 'student';

-- 查 sno 列的详细统计信息,NULL 占比、唯一值这些都能看清
select 
  attname as 列名,
  round(stanullfrac * 100, 2) as NULL值占比(%),
  case when stadistinct < 0 then round(-stadistinct * 100, 2) || '%' else stadistinct::text end as 唯一值占比,
  stawidth as 平均宽度(字节)
from sys_statistic s
join sys_attribute a on s.starelid = a.attrelid and s.staattnum = a.attnum
where s.starelid = 'student'::regclass and a.attname = 'sno';

四、扩展统计信息:解决多列相关性的"痛点"

单列统计信息根本看不出多列之间的关联------比如 a 列和 b 列始终满足 a = b,但优化器不知道,查 a=1 and b=1 时就会估错结果集大小。这时候就得靠扩展统计信息来补这个坑!

4.1 扩展统计的三种类型

  1. 函数依赖 :比如 b 列的值全由 a 列决定(a = b),查多列条件时能精准估数,不瞎猜。
  2. 多元 N-Distinct 计数 :统计多列组合的唯一值数量(比如 group by a,b 时的真实分组数),避免估错分组数。
  3. 多元 MCV 列表:统计多列组合的高频值,优化多列条件查询的选择率估算,让执行计划更优。

4.2 实战代码:创建与使用扩展统计

1. 场景准备:存在函数依赖的表
sql 复制代码
-- 创建表 t,a 和 b 列满足 a = b(典型的函数依赖)
create table t(a int, b int);
insert into t select i%100, i%100 from generate_series(1, 10000) s(i);
analyze t;

-- 没创建扩展统计时,查 a=1 and b=1(优化器估数贼不准)
explain analyze select * from t where a=1 and b=1;
-- 输出会显示预估行数 1 行,实际 100 行,估数偏差大到离谱
2. 创建函数依赖扩展统计
sql 复制代码
-- 创建函数依赖类型的扩展统计,让优化器知道 a 和 b 有关系
create statistics stts_dep(dependencies) on a, b from t;

-- 必须执行 analyze 才生效,别忘这一步!
analyze t;

-- 再查一次,优化器能正确估算返回 100 行,终于不瞎猜了
explain analyze select * from t where a=1 and b=1;
3. 创建多元 N-Distinct 统计(优化 group by 场景)
sql 复制代码
-- 没创建扩展统计时,group by a,b 估数不准
explain analyze select count(*) from t group by a,b;
-- 优化器可能估成 1000 组,实际就 100 组,差了 10 倍

-- 创建多元 N-Distinct 扩展统计,统计多列组合的唯一值
create statistics stts_ndist(ndistinct) on a,b from t;
analyze t;

-- 再查,分组数估数精准,执行计划也更优了
explain analyze select count(*) from t group by a,b;
4. 创建多元 MCV 统计(优化多列条件查询)
sql 复制代码
-- 创建多元 MCV 扩展统计,记录多列组合的高频值
create statistics stts_mcv(mcv) on a,b from t;
analyze t;

-- 多列条件查询,选择率估算更精准,执行速度直接提上来
explain analyze select * from t where a=5 and b=5;

-- 查扩展统计的详细数据,确认高频值是不是真被记录了
select * from sys_statistic_ext_data where statid = (select oid from sys_statistic_ext where statname = 'stts_mcv');
5. 管理扩展统计对象
sql 复制代码
-- 查所有已创建的扩展统计,看看有没有没用的
select 
  statrelid::regclass as 表名,
  statname as 统计名,
  stattype as 统计类型,
  created as 创建时间
from sys_statistic_ext;

-- 删掉不需要的扩展统计,省点资源
drop statistics if exists stts_dep;

五、统计信息调优避坑指南:这些错误别踩!

5.1 大表采样偏差导致统计不准

  • 问题:大表采样比例太低,数据分布信息失真------比如直方图缺了关键区间,优化器直接估错。
  • 解决:提高采样率或全量收集,必要时调整默认采样容量,别抠这点时间,准头更重要!
sql 复制代码
-- 给大表提采样率(比如采样 20%),保证统计信息准
ANALYZE student TABLESAMPLE SYSTEM (20);

-- 调整默认采样容量(改完要重启数据库才生效)
alter system set default_statistics_target = 200;
select pg_reload_conf();

5.2 长期不更新统计信息

  • 问题:有些历史表数据早变了,但统计信息还是几年前的,优化器拿着旧数据瞎决策,能不慢吗?
  • 解决:设个定时任务,每天凌晨自动收集大表统计信息,一劳永逸!
sql 复制代码
-- 定时任务示例(通过 crontab 每天凌晨 2 点跑,不影响业务)
0 2 * * * psql -U username -d dbname -c "ANALYZE student; ANALYZE order_info; ANALYZE product;" >> /var/log/kingbase_analyze.log 2>&1

5.3 忽略多列查询的扩展统计

  • 问题:多列联合查询时,只靠单列统计,优化器看不出列之间的关联,选率估算偏差贼大。
  • 解决:对经常用来连接、过滤的列组合,赶紧建扩展统计,别嫌麻烦!
sql 复制代码
-- 给订单表的 user_id + order_date 列组合建扩展统计,兼顾函数依赖和高频值
create statistics order_ext_stats(dependencies, mcv) on user_id, order_date from order_info;
analyze order_info;

5.4 创建索引后未更新统计信息

  • 问题:新建索引后,优化器压根不知道有这索引,还是傻乎乎走全表扫描,白建了!
  • 解决:创建索引后立马执行 ANALYZE,让优化器知道有这"新武器"。
sql 复制代码
create index idx_student_sno on student(sno);
ANALYZE student(sno); -- 只更这列的统计,效率更高,不浪费时间

-- 验证下索引是不是被优化器认出来了,别白忙活
explain analyze select * from student where sno = 100;

六、统计信息调优流程:从排查到优化的完整步骤

  1. 定位问题 :用 EXPLAIN ANALYZE 对比预估行数和实际行数,差距超 50%,基本就是统计信息的锅;
  2. 更新统计 :针对目标表执行 ANALYZE,大表记得指定采样率,别硬刚全量;
  3. 验证效果 :再跑一遍 EXPLAIN ANALYZE,看看执行计划是不是变优了;
  4. 进阶优化:要是多列查询还不准,就给相关列组合建扩展统计;
  5. 长期维护:调调自动收集参数,或者设个定时任务,保证统计信息一直准。

总结

统计信息就跟 KingbaseES 优化器的"眼睛"似的,只有信息精准,优化器才能看清数据、选对执行计划。日常调优时,别全指望自动收集------省心归省心,但关键场景(大表批量更新、多列查询)必须手动干预:用主动收集保证统计信息实时准,用扩展统计解决多列相关性的坑。把这些技巧用到位,就能从根上提升 SQL 执行性能,让数据库跑得又快又稳!

相关推荐
-XWB-5 小时前
【Oracle】Oracle诊断系列(3/6):性能瓶颈定位——从SQL到I/O的全面分析
数据库·sql·oracle
2501_907136825 小时前
批量重命名工具 Double12 Renamer -可正则、翻译
数据库·redis·缓存
猿小羽5 小时前
Spring Boot 2 + Flyway 最佳实践:多数据库配置与迁移规范
spring boot·mysql·postgresql·oracle·flyway·sql server·数据库迁移
xuefuhe5 小时前
postgresql xmin xmax cmin cmax ctid
大数据·数据库
是桃萌萌鸭~5 小时前
oracle 排查卡顿相关日志
数据库·oracle
wuxi_joe5 小时前
一家研发制造企业的“软件进化史”
大数据·数据库·制造
草莓熊Lotso5 小时前
远程控制软件实测!2026年1月远程软件从“夯”到“拉”全功能横评
运维·服务器·数据库·人工智能
冰暮流星5 小时前
sql之删除与软删除
数据库·sql
沐雪架构师5 小时前
LangChain 1.0 记忆管理:短期与长期记忆详解
服务器·数据库·langchain