☰
KingbaseES存储结构详解:数据页、索引与WAL机制
2026/9/26 17:30:04 网站建设 项目流程

先做个说明:市面上讲KingbaseES的文章不少,但大部分都在讲SQL语法、备份恢复,真正深入到存储内部结构的内容非常少。我研究KingbaseES的存储结构有一段时间了,期间翻过官方文档、对照过Oracle和PostgreSQL的实现,也在实际项目中排查过几次存储相关的问题,这篇就把积累的东西一次讲清楚。内容包括逻辑存储层的设计、物理文件组织、页内部结构、索引存储机制、WAL日志机制,以及实际操作中一定会遇到的膨胀、损坏、空间排查等问题。看完之后,你对金仓数据库“数据到底怎么放的”会有一个完整清晰的认识,排查问题时也能直接上手。

1. KingbaseES存储架构概览:逻辑与物理双层的映射关系

1.1 逻辑存储层级:从数据库实例到数据页

KingbaseES的整体存储结构,我觉得可以概括为一句话:逻辑上分层,物理上分块。逻辑层次的顶层是实例(Instance),一个实例对应一个运行中的数据库服务进程组,通常监听一个独立端口。实例下面是多个数据库(Database),不同数据库之间逻辑隔离,这一点和Oracle的“一个实例对应一个库”有本质区别,反而更像PostgreSQL。再往下是表空间(Tablespace)、Schema、表(Relation),最后落到数据页(Page/Block)这一层。

我把这个层级关系整理成一张表,方便大家对照记忆:

层级对应物理对象作用域说明
实例(Instance)数据目录集合、共享内存段、后台进程管理所有数据库,对应一个data目录
数据库(Database)data/base/xxx 子目录逻辑隔离,权限隔离
表空间(Tablespace)独立目录(非base下)跨库共享存储位置
Schema/表(Relation)表空间内的若干文件业务数据组织单元
数据页(Page/Block)文件内固定大小块(默认8KB)读写的最小单位

这里面有个关键点:很多从Oracle转过来的DBA,第一次接触金仓时都会问“表空间对应哪个数据文件?是不是一个表空间一个文件?”。实际上金仓的表空间和Oracle不太一样,它逻辑上确实有“表空间”这个概念,但物理上并不强制每个表空间对应一个独立文件,而是对应一个操作系统目录。表空间里的表,会以独立文件的形式存放在这个目录下。所以你在金仓里执行CREATE TABLESPACE时,指定的其实是“路径”,而不是Oracle那种“数据文件路径+大小”。

1.2 物理存储目录:base目录、oid与relfilenode的对应关系

搞清楚了逻辑层,再看物理层就顺了。KingbaseES的数据目录(通常叫data)下面,核心目录是base、global、pg_wal(早期版本叫pg_xlog)、pg_tblspc、pg_stat等。base目录里每个子目录的目录名是一个数字,这个数字就是“数据库OID”。你连上某个库之后执行:

SELECT oid, datname FROM pg_database;

拿到的oid就能直接去data/base/下找到对应的目录。所以排查一个库占了多少空间,最简单粗暴的办法就是直接统计base下面对应目录的总大小,比如:

du -sh /data/kingbase/base/16405

这里16405是数据库OID。

global目录存放的是集群级的共享对象,比如pg_control、全局系统表等。pg_tblspc目录里放的是软链接,指向你创建表空间时写的那个物理路径。这个设计和PostgreSQL一模一样,而不像Oracle那样有个dbf文件列表需要维护。

再往深一层,每个表或者索引在物理上是一个文件,文件名称为relfilenode。你执行:

SELECT pg_relation_filepath('你的表名');

返回的就是类似base/16405/16783这样的路径。这个16783就是当前的relfilenode。在KingbaseES里,当表执行过VACUUM FULL或者CLUSTER之后,relfilenode会发生变化,因为文件被重建了。这个细节很重要——你如果监控发现在线巡检时表文件的mtime变了,不一定是有业务在写,也可能是有人执行了重构类的操作,不要误判为异常写入。

1.3 存储结构设计的兼容性思路

金仓的存储引擎内核来源于PostgreSQL,但为了兼容Oracle,又做了不少封装。我在实际使用中感受最深的一点是:很多Oracle开发的SQL和PL/SQL在KingbaseES上可以直接跑,但涉及存储特性的操作(比如你直接去读dba_data_files来查数据文件),返回的结果其实是金仓做了一层视图映射。这意味着你可以用Oracle习惯的视图查,但底层实现完全是另一套。

这种“兼容”设计带来的一个实际问题是:网上很多教程直接照搬PostgreSQL的存储说明来套金仓,容易踩坑。比如PostgreSQL里pg_current_wal_lsn()这样的函数,金仓早期版本改过名字,现在版本基本保留了pg_current_wal_lsn,但某些老版本要写sys_current_wal_lsn或者别的名字,各个大版本之间不完全一致。所以你在研究金仓存储结构时,最好是对着目标版本的官方文档来验证,不要只看泛用性的资料。

注意:金仓的版本号体系比较复杂,V8系列下又分V8R3、V8R6等子版本,存储细节有差异。下面我讲的内容以目前较常见的V8R6为主,但凡是跨版本有差异的点,我都会额外说明。

2. 页(Page)的内部布局:数据在磁盘上的最小组织单元

2.1 固定页大小与页内分区

KingbaseES默认数据页大小是8KB(编译时通过BLCKSZ控制,默认值是8192字节)。整个页结构分为四个区:页头(PageHeaderData)、行指针数组(ItemIdData)、空闲空间(Free Space)、元组数据区(Tuple Data)。页头和行指针数组是从页的头部向下生长的,元组数据是从页的尾部向上生长的,中间就是空闲空间。空闲空间耗尽时,页就不能再插入新行了,需要往新页里写。

页头里包含的关键信息包括:页的LSN(最近修改该页的WAL记录位置)、页的检查点位(pd_checksum)、页内元组数量(pd_lower其实就是空闲空间起始位置,pd_upper是空闲空间结束位置等)。如果你用类似pageinspect的插件(金仓对应功能也有),可以直接查看这些结构。我在分析表膨胀问题时,经常先看pd_lower和pd_upper,算一下空闲空间占比,就能判断页是不是“假满”。

关于页大小,我想说一点:8KB在OLTP场景下是比较合适的,它兼顾了缓存效率和行大小适配性。如果单行数据非常大(比如超过2KB),你可能会关心是否要调大块大小,但是KingbaseES的块大小必须在编译时指定,运行期无法修改。所以如果是纯Oracle迁移场景,原来依赖大块缓存优势的业务,迁移过来之后可能需要重新评估缓冲命中率——这是存储结构差异带来的性能适配问题。

2.2 行数据(Heap Tuple)的物理组织方式

每个元组(行)在页内的存放,不是像Oracle那样“列表管理全部数据”,而是通过行指针数组 + 元组实体两级定位。页头后面是一组ItemIdData,每个4字节,其中包含元组实体在页内的偏移量和长度。元组实体本身在页尾部,包含元组头(HeapTupleHeaderData)和实际字段数据。

堆元组头里有两个值得重点解释的字段:t_xmin和t_xmax。在金仓的MVCC机制里,每一行都记录了插入和删除/更新它的“事务号”。这也是理解“更新等于删+插”的关键:在KingbaseES默认的堆表引擎里,执行一次UPDATE,物理上的结果大概率是“旧元组被标记为删除(t_xmax被设置为新事务号,但数据还在)+ 新元组插入到页里”。这跟在Oracle里直接原地覆盖完全不同,也直接引出了后面章节要讲的“表膨胀”问题。

还有一个细节,KingbaseES支持一种“TOAST”(The Oversized-Attribute Storage Technique)机制,专门处理大字段。当一行的某个字段太大,比如一个几MB的文本或者二进制内容,直接塞进堆元组里会让整个页都放不下。此时引擎会自动把大字段值拆分成多个块(默认约2000字节每块),存到独立的TOAST表中,原行里只保存一个指向TOAST表的OID和指针。这个过程对应用是透明的,但影响颇大:如果业务表大量存大对象,物理文件会额外多出一个_toast后缀的文件,空间统计和清理策略都必须关注它。

2.3 可见性判断机制:老版本数据的存储与清理

因为有了t_xmin和t_xmax,判断一行“是否可见”就变成了比较事务快照与这些事务号的大小关系。我一直觉得这是KingbaseES存储结构里最核心的设计:它把“并发控制”和“物理存储”绑定在了一起,也让一切空间膨胀都源于MVCC这个本质。

当一个事务执行DELETE后,被删除的行其实还躺在数据页里,只是t_xmax被标了新事务号,快照老的查询仍然能读到它。只有等到这个删除事务以及更老的读事务全部结束,VACUUM才会把这种“死亡元组”占用的空间标记为可复用。而VACUUM不会立即把空间还给操作系统,它只是把页内部的空间标记为空闲,文件整体大小不变。这就是为什么你VACUUM之后看du文件还是那么大,必须执行VACUUM FULL才能收缩文件。

顺便补充一个和存储布局直接相关的使用建议:频繁UPDATE的业务表,页内的空闲空间会非常零碎,新插入的行可能无法紧凑排列,导致页利用率下降。此时合理的FILLFACTOR(默认100)需要调整,给页预留一些UPDATE空间,这能明显减少页分裂和死元组堆积。比如一张表经常把行的某个字段从一个较短字符串更新为更长字符串,FILLFACTOR=80往往能比默认值减少30%以上的行迁移和页分裂。这个参数在存储布局上,本质就是“人为改制UPSERT空间”。

3. 表空间与数据文件规划:从创建到运维的完整路径

3.1 表空间创建与重定向

金仓里创建表空间,语法很简洁:

CREATE TABLESPACE tbs_app LOCATION '/data/kingbase/tbs_app';

执行这个语句前,目录必须存在且为空,而且系统用户(kingbase用户)要有该目录的写权限。创建完成后,你可以在建表时指定表空间:

CREATE TABLE t1(id int, name text) TABLESPACE tbs_app;

创建完表之后,去/data/kingbase/tbs_app目录下你会看到一堆以数字命名的文件,这些就是表对应实际数据文件。这里有一个实践细节:切换表空间不等于迁移数据文件。如果你想把已有表从默认表空间挪到新表空间,需要执行:

ALTER TABLE t1 SET TABLESPACE tbs_app;

这条修改会在物理层面把表文件从旧位置复制到新位置,并更新系统目录,整个过程要加锁但一般比较快。如果表示几十GB的大表,这个过程会重启IO压力,最好安排在业务低谷执行。

和金仓相关的还有一个操作:从Oracle迁移时,如果原库的某些表分布在不同的表空间,DBA通常习惯性地也想在金仓建同名表空间来保持迁移一致性。我的实际建议是:不要完全照搬Oracle的表空间规划。金仓没有Oracle那种分区表“每个分区独立表空间”的硬件性能需求,表空间更多是用来做存储位置隔离——比如把热点业务表放到SSD盘、把归档历史表放到机械盘。规划时按存储介质和应用生命周期去分,通常两三个表空间就够了。

3.2 数据文件大小与自动扩展机制

金仓堆表文件默认大小是1GB。当表超过1GB时,文件会继续扩展成relfilenode.1、relfilenode.2这样的分段文件。这一点和PostgreSQL一样,但和Oracle(默认单个数据文件通常设为32GB甚至更大)有显著差异。实际运维时需要注意:文件一多,备份恢复、慢查询全扫描都会受到一定影响,因为操作系统和数据库都要维护更多句柄。

文件扩展的触发条件是“当前文件末尾页已满,需要新页”。这种扩展操作会申请新的文件段,但不会立即发生磁盘空间写满,而是随着写入逐步增长。在查询方面,SELECT pg_relation_size('表名')返回的是当前表的主堆文件总大小(所有段之和),不包括索引和TOAST。我一般排查空间时喜欢一次看全:

SELECT pg_size_pretty(pg_total_relation_size('big_table')) AS total_size, pg_size_pretty(pg_relation_size('big_table')) AS heap_size, pg_size_pretty(pg_total_relation_size('big_table') - pg_relation_size('big_table')) AS index_toast_size;

如果index_toast_size占比惊人地高,就需要单独排查索引膨胀和TOAST了。

关于“文件满了会不会自动扩展”:金仓对数据文件的增长基本不做限制,限制来自文件系统。真正影响可用性的反而是WAL目录(pg_wal)的增长。如果某个库大量写数据,WAL文件会不停产生和归档,如果归档失败或者wal_keep_segments配置过大,pg_wal目录会被撑满,数据库会直接罢工。这种表现很容易让新手误判为“数据文件满了”,其实是WAL空间的问题。

3.3 分区表与表空间的配合使用

金仓分区表在物理存储上也遵循“一个分区一个独立文件”的规则,所以分区对存储结构的影响是显而易见的:它能有效阻止单个表文件无限膨胀到超出文件系统的最大文件数限制,同时让“只读老分区”的物理数据可以独立搬迁到慢速存储。

我在本地测试时验证过一个情况:在使用RANGE分区的情况下,每天一个分区,按月归档。归档逻辑很简单,把老月份的分区DETACH,然后单独备份该分区的表空间目录。这比全表逻辑删除要可靠得多,因为物理文件可以单独控制。

但需要注意:金仓的分区表在早期版本中,对“分区裁剪”的优化不如Oracle成熟,某些复杂条件查询可能要扫描所有分区,此时你会发现IO压力非常大——“明明我只查上个月的数据,为什么磁盘读取那么猛?”这本质上还是物理存储层次的问题。所以分区的时候要注意,查询条件尽量写成能在WHERE里BETWEEN这种范围形式,并且在每个分区上建好对应的本地索引,避免走全分区扫描。

4. 索引存储结构:B+Tree物理实现与膨胀原理

4.1 B+Tree索引的页内布局

KingbaseES默认的堆表索引是B+Tree结构,在物理存储上,索引也是一个独立的文件,内部同样按8KB页组织。B+Tree的页面分为三种:根页、内部页(分支页)、叶页。和Oracle索引不同,金仓的索引叶页里存的是索引键值 + 对应的堆表行的物理位置(TID:页号+偏移量),而不是像Oracle那样通过ROWID直接物理定位。

查询过程是有趣的:先走索引找到匹配的TID,然后通过TID回表读取堆页。如果查询要返回的列不在索引里,就必然有一次表扫描(回表)。这个机制决定了“索引覆盖”的重要性——如果你能用“索引包含列”或者复合索引把查询需要的列都覆盖到,就能省掉回表IO,性能差好几倍。

索引页的内部结构比堆页稍微复杂,但核心还是“页内键值有序排列 + 页间指针链接”。B+Tree的特征是数据都存放在叶层,内部页只放键值和子页指针,因此整个索引的高度通常只有3~4层,千万级数据的查询也能在几次页读之内完成。实践中的一个关键心得是:不要把索引建得过长,索引键值越长,单个页能放下的键越少,树的高度越高,IO次数越多。比如一个varchar(200)的建索引成本,远远高于int索引,尽量不要超过32字节的边界。

4.2 索引膨胀的机制与影响

索引膨胀和表膨胀的根源相同,都是MVCC留下的死元组未及时清理。当堆表里的死元组被VACUUM清理时,索引里指向这些死元组的指针也会被标记为过期,但索引页里的空间回收通常不及时。更麻烦的是,如果堆表UPDATE频繁导致索引键值变更,索引会不断插入新键、删除旧键,页内出现大量碎片空间。

有一个非常经典的现象:表只有几万行,但某个索引文件却占了500MB。这种“索引膨胀”一般出现在高并发UPDATE且高频小事务的场景。排查的时候,可以用:

SELECT pg_size_pretty(pg_relation_size('idx_name')) AS idx_size;

和表大小对比感受一下。解决索引膨胀有两个方法:

第一,REINDEX INDEX idx_name,全量重建索引,杀敌一千但会持有写锁,大索引上执行会造成业务停摆,必须谨慎。

第二,定期VACUUM并及时回收,配合老版本里CONCURRENTLY参数。金仓支持并发重建索引吗?其实V8R6已经类似PostgreSQL提供了REINDEX INDEX CONCURRENTLY的语法,但执行耗时更长,而且要占用更多临时空间,你需要自行测试权衡。我的建议:生产环境大表的索引重建,优先用并发方式,做个维护窗口,能接受长时间占用就上。

4.3 FILLFACTOR在索引和表上的差异化设置

前面提到过表的FILLFACTOR设置,索引的FILLFACTOR同样重要,而且语义不同。对B+Tree索引而言,FILLFACTOR越低,初始构建时页内预留的空闲空间越多,将来插入新索引项时,页分裂的概率越低。

对一张频繁INSERT且不太UPDATE的表,索引的FILLFACTOR可以设到90,这样索引页既有一定的余地应付随机插入,又不会因为太空导致索引膨胀。对于频繁UPDATE被索引列的表,建议将索引的FILLFACTOR设得更低一些,比如70~80,这样更新时索引键值迁移会有更多缓冲空间。

我曾经接手过一个项目,业务每天早高峰大量UPDATE一张订单表,系统卡顿严重。排查时发现其中一个组合索引的叶页几乎都满了(实际读到的avg_leaf_density接近95%),UPDATE触发大量的页分裂和旧指针清理,整个系统被索引维护拖累。后来把该索引FILLFACTOR重建为75,问题明显缓解——虽然索引空间多了三分之一,但明显改善了SQL执行的稳定性。

注意:FILLFACTOR的修改,对已经存在的索引必须重建才能生效,不能只改参数不重建。这是个容易踩的坑。

5. WAL预写日志与崩溃恢复:存储可靠性的底层支柱

5.1 WAL文件的结构与管理方式

WAL(Write-Ahead Logging)是KingbaseES保证数据不丢的基石。它的语义是:任何用户数据的修改,先写WAL日志,再改数据页。这样做的好处是,不用每次提交都把脏页刷到磁盘,只需要把日志刷掉就行;崩溃后靠WAL重放就能恢复。

WAL文件默认在data/pg_wal目录下,每个文件大小默认16MB(编译时以XLOG_SEG_SIZE控制)。文件命名是24位十六进制时间线ID+日志序号,所以你在目录里会看到一长串像00000001000000000000002F这样的文件。每个WAL文件内部按8KB页组织,页内是一个接一个的日志记录。每一条记录都包含:头部(记录类型、长度、事务ID、上一条记录的指针)+ 实际的页面数据变更或逻辑信息。

WAL机制对存储结构有一个非常直接的影响:数据页越分散,一个逻辑操作需要写的WAL记录越多吗?其实不一定。WAL记录的是页面的变更或一些重要事件,跟你操作的页是否集中没有必然关系,但如果你频繁更新相同页面,WAL里会积累大量重复的整页写(full page write)。所以KingbaseES有一个“全页写”机制:在基准备份后的第一次修改时,把整个页的镜像记到WAL里,用于防止部分写导致崩溃后无法恢复。这个选项由full_page_writes控制,默认开启,不能随意关闭,否则恢复时可能遇到页损坏。

实际运维中,WAL目录的IO压力和存储配置密切相关。我在生产环境建议:务必把pg_wal放在独立的高性能磁盘上,最好是带备电的SSD,否则一个事务风暴就能把磁盘IO打满,甚至造成全库卡死。另外WAL目录要留足够的余量,一般至少给数据总量的10%~20%作为本底空间,高峰写入时要按事务量动态调整。

5.2 检查点(Checkpoint)机制的存储影响

每过一段时间,数据库会执行一次检查点(Checkpoint),把WAL里已记录的修改实际刷到数据文件中,然后推进pg_control里的“检查点位置”。检查点完成后,更早的WAL文件理论上就可以清理或覆盖了。

这里有个关键体验:如果你配置了checkpoint_completion_target=0.9,数据库会尽量把检查点的写脏页操作分散到整个检查点周期内,避免突然的IO尖刺。但如果你是机械盘,大表频繁更新时,检查点周期内的持续写IO依然会明显。存储结构上体现为:被修改的页会在一个周期内集中落盘,数据文件写入量在时间轴上并不均匀。

我在一次仓库优化中,把max_wal_size从默认的1GB调到了4GB,同时拉长了检查点间隔,明显减少了磁盘尖刺。副作用是WAL目录占用的空间变大了。后来我评估了一下:如果业务能接受故障时丢更多WAL重放时间(即恢复时间RTO变长),这个调整就非常划算;如果不能接受,则要权衡。这个平衡是存储结构中“WAL大小vs数据落盘频率”的典型取舍。

5.3 归档日志与备份的存储关系

如果你的库开了归档模式,WAL日志在覆盖前会先被复制到归档目录。归档日志的存储量往往能超出预期。我见过不少客户,业务数据总共才200GB,归档目录却积压了超过1TB。原因往往是:归档命令(archive_command)执行失败,或者存储端上传速度跟不上WAL产生速度,导致WAL无法清理,最后pg_wal和归档目录双双爆炸。

在存储结构层面,归档期间还会出现一个有意思的现象:WAL段文件在被覆盖之前,必须被完整归档,如果某个WAL段因为文件系统元数据问题偶尔失败,数据库会反复重试,导致后续WAL继续堆积。排查时,我建议先看归档命令的日志,再看pg_stat_archiver视图:

SELECT * FROM pg_stat_archiver;

如果failed_count持续上涨,基本可以断定归档链路出了问题。这时不要拖,赶紧修复外部存储的写入问题,并考虑临时手动清理一部分已经成功归档的WAL段(在有备份的前提下)——否则一旦磁盘满,数据库直接拒绝所有写操作,恢复代价非常大。

6. 实际运维中的存储结构问题排查手册

6.1 表膨胀的处理流程与VACUUM策略

表膨胀是我在日常运维中遇到频率最高的存储结构问题,没有之一。观察到表文件在不断增大,但实际“活数据”并没有那么多时,可以按下面的流程走一遍:

先看VACUUM状态和死元组数量:

SELECT relname, n_live_tup, n_dead_tup, last_vacuum, last_autovacuum, last_analyze FROM pg_stat_user_tables WHERE relname = 'your_table';

再估计膨胀率。虽然没有一个官方SQL能百分百准确给出“膨胀率”,但用pg_relation_size对比n_live_tup的平均行宽,可以推算“理想大小”和“实际大小”的差距。比如一张表活数据约50万行,平均行宽500字节,理想堆文件大小约500 * 50万 ≈ 250MB,但实际文件1GB,基本就是膨胀了。

处理策略分两级:轻度膨胀,跑普通VACUUM就可以回收页内空间供后续复用,文件大小不会下降;重度膨胀,必须VACUUM FULL或者pg_repack。但VACUUM FULL会锁表并重写文件,在业务高峰期绝对禁止。如果你不想业务中断,可以考虑pg_repack,它通过额外日志表的方式在线重排数据,对业务影响小很多,但需要额外安装插件和预留一倍表空间。

关于自动清理(Autovacuum)配置,我建议:

参数常用设置说明
autovacuum_max_workers3~5并发清理的Worker数量
autovacuum_vacuum_threshold50触发阈值基数
autovacuum_vacuum_scale_factor0.05~0.1占比系数,大表建议调低
autovacuum_vacuum_cost_delay10ms~20ms限速值,避免清理风暴
autovacuum_vacuum_cost_limit200~1000总成本上限

大表的Autovacuum触发计算是:死元组数超过threshold + scale_factor * 元组总数时触发。比如10GB的表,如果scale_factor=0.1,要积累10%的死元组才会触发,这个容忍度太高了,会造成大量死元组堆积。对这种大表,我建议单独设置表级参数:

ALTER TABLE big_table SET (autovacuum_vacuum_scale_factor = 0.01);

6.2 文件系统与页损坏的检测手段

存储结构层的损坏,会影响数据库正常运行。金仓提供了pg_checksums工具(对应PostgreSQL 12+的特性)来检查和启用页校验和。如果启用了数据校验和,每次页读/写时都会校验pd_checksum,发现哪页坏了就能快速定位。

使用方式是在停库状态下执行:

pg_checksums -d /data/kingbase -r

也可以只用-c检查而不重写。运行时如果遇到“invalid page in block xxx of relation base/.../...”这类日志,大概率是某个数据文件发生了损坏。这时我的操作路径是:

  1. 先从备份中恢复损坏的文件。
  2. 如果库还在运行,把损坏的表或索引下线,对应文件标记坏页,用VACUUM FULL尝试重写该文件。
  3. 如果损坏发生在系统表上,恢复难度陡增,应尽快联系原厂支持,或者利用最近的物理备份恢复。

特别提示:机械盘坏道、虚拟机漂移、内存ECC错误都可能导致页损坏。我见过一个客户的SSD盘使用过久后静默损坏,数据库日志里零星出现坏页错误,但应用只偶发报错。这种“隐性损坏”最可怕,因为你不发现,它就会慢慢扩散,所以启用checksum+ 定期巡检文件完整性,是非常必要的。

6.3 快速定位存储占用大户的SQL

最后分享一个日常巡检一定用得上的SQL集合。我总在故障发生时快速定位“到底哪个对象占满了我的空间”,这组查询能使排查效率提升很多:

按整库总大小排前十的表:

SELECT schemaname, relname, pg_size_pretty(pg_total_relation_size(relid)) AS total_size, pg_size_pretty(pg_relation_size(relid)) AS heap_size FROM pg_stat_user_tables ORDER BY pg_total_relation_size(relid) DESC LIMIT 10;

查当前有哪些表空间,各自落在哪个物理目录:

SELECT spcname, pg_tablespace_location(oid) AS location FROM pg_tablespace;

查WAL目录大小与归档状态:

SELECT * FROM pg_stat_archiver;
du -sh /data/kingbase/pg_wal

查所有索引大小,并按大小排序,快速定位索引膨胀:

SELECT schemaname, tablename, indexname, pg_size_pretty(pg_relation_size(indexrelid)) AS idx_size FROM pg_stat_user_indexes ORDER BY pg_relation_size(indexrelid) DESC LIMIT 20;

这套查询适用于任何版本的金仓,因为它们基于系统视图,基本都兼容。我平时做巡检脚本,基本就是把这些SQL串起来,每周跑一次输出报告。

最后再分享一个实际经验:金仓的存储结构虽然和PostgreSQL很像,但真要深入还是得用官方自带的工具和视图,不要只看通用教程。尤其是遇到版本差异时,先确认你的内核小版本,再对照官方文档做验证。我用金仓这段时间,最大的感受是它的存储内核足够稳,但“稳”的前提是你要真正理解它背后是怎么落盘、怎么管理空间的。把页结构、WAL、VACUUM、膨胀这几条线串起来,运维中九成以上的存储问题都能做到快速判断、精准处理。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询