StarRocks查看每张表存储占用:系统表+SQL实战
发布时间:2026/9/30 4:58:50来源:尧图网络
先说说我自己遇到的场景。某天下午测试环境磁盘告警我登录StarRocks想看看是哪些表在膨胀结果发现一个尴尬的事实界面上能看到集群总容量、BE节点的数据目录大小但真要到“每张表到底占了多少G”这个粒度默认命令居然给不出一个干净利落的答案。折腾了一圈把information_schema里的几张系统表啃明白之后才算找到正规军。这篇就聊聊 StarRocks 如何查看每张表占用的存储包括背后的存储结构、官方系统表口径、实操SQL、以及我在排障过程中踩过的坑。这个主题适合三类人日常维护 StarRocks 集群的运维、需要做容量规划和成本核算的数据平台工程师、以及遇到磁盘告警但不知道从哪张表下手的开发同学。看完之后你至少能写出第一条“全表存储占用清单”SQL并且知道为什么有些统计数字和你预期的对不上。1. 先搞清楚StarRocks 里的“表大小”到底怎么算1.1 一张表的数据是怎样落盘的想查表大小先得明白 StarRocks 的存储分层表Table→ 分区Partition→ 分桶Tablet→ Rowset → Segment。这里最关键的一层是 Tablet它是 StarRocks 中数据复制、均衡、迁移的最小物理单元。每个 Tablet 会按照副本数复制多份分散到不同的 BE 节点上而每个 BE 节点上真正落盘的东西就是 Tablet 对应目录下的 Rowset 文件和 Segment 数据文件。用大白话理解一张表好比一个大仓库分区是楼层分桶Tablet是楼层里的独立房间Rowset 是房间里的一批货Segment 是货架上的具体箱子。系统表里统计的数据大小本质上就是统计这些“箱子”加在一起的体积。因为数据是分布式的同一张表的 Tablet 可能散落在十几台 BE 上所以“表大小”天然是一个需要聚合计算的值。这也解释了为什么简单的SHOW TABLES看不到 size 字段——存储统计必须跨节点汇总不可能存在一张普通元数据表里直接给你。1.2 三种口径逻辑大小、单副本大小、物理占用我在查容量时发现很多人对“表大小”的理解其实有偏差。StarRocks 的存储统计至少要区分三种口径逻辑大小导入数据体积你通过 Stream Load、Broker Load 等导入的原始数据量未经过压缩是“业务视角”的大小。单副本大小系统表展示值BE 上某个 Tablet 数据文件实际占用的磁盘空间。StarRocks 默认使用 LZ4 等压缩算法所以这个值比原始导入体积小不少。物理占用集群视角真实消耗单副本大小乘以副本数。默认副本数为 3也就是说一份数据理论上会在集群里占三份磁盘。information_schema系统表返回的DATA_SIZE一般指的是第二类——单副本的物理文件大小已经包含了压缩效果。很多人拿这个值去核对集群总容量发现乘上副本数才对得上就是因为没区分这三种口径。1.3 为什么没有一个现成的 table_size 字段这也是新手最容易困惑的地方。MySQL 里查information_schema.tables有DATA_LENGTHStarRocks 早期版本参考了这套设计但实际用起来会发现不准原因有两个一是 StarRocks 是 MPP 架构同一个表的统计信息分散在多个 BE 上FE 需要周期性地收集各 BE 的 Tablet 报告才能汇总出全局值。这个收集过程有延迟不是实时精确值。二是 StarRocks 的部分系统表在实现时更偏重“表结构元数据”而不是“存储统计”真正存储维度的信息被拆到了另外的表中。所以你需要组合查询tables_config、table_sk等系统表才能拼出完整答案。2. 官方入口information_schema 两张核心系统表2.1 tables_config拿“表ID到表名”的映射StarRocks 的系统表里很多存储统计表只记录TABLE_ID不直接给你表名。所以第一步通常是先查information_schema.tables_config拿到表名和表 ID 的对应关系。SELECT TABLE_ID, TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE, KEY_TYPE, REPLICATION_NUM, DISTRIBUTED_BUCKETS FROM information_schema.tables_config LIMIT 20;这张表的特点是每个字段都有用KEY_TYPE告诉你表是主键表、聚合表还是明细表REPLICATION_NUM表示副本数计算物理占用时要用到DISTRIBUTED_BUCKETS是分桶数能辅助判断表是否建得合理。它本身不存大小但它是所有存储统计查询的“字典表”。2.2 table_sk表级存储统计的正确入口真正存“大小”的系统表在较新的 StarRocks 3.x 版本里叫information_schema.table_sk某些版本也叫table_statistics或类似命名它的粒度是“每个 Tablet 一条记录”。重要字段如下字段名含义TABLE_ID表 ID关联 tables_configPARTITION_ID分区 IDTABLET_IDTablet ID分桶后的最小单元NUM_ROWS该 Tablet 的行数DATA_SIZE该 Tablet 数据文件的大小单副本单位字节CREATE_TIME / UPDATE_TIME元数据记录时间用于判断统计新鲜度这个表的设计很有意思它不是表级汇总而是 tablet 级明细。也就是说你可以按TABLE_ID分组求和得到表级存储也可以按PARTITION_ID分组得到分区级存储。这让容量分析灵活了很多。2.3 不同版本怎么选如果你的 StarRocks 版本比较老可能没有table_sk。这时有两个备选方案一是查询information_schema.be_tablets这个视图也会返回TABLE_ID、BE_ID、DATA_SIZE、ROW_NUM区别是它还带了 BE 节点维度可以用来做节点均衡分析二是直接用SHOW DATA命令它会返回每张表的 size 和副本数虽然粒度粗但胜在简单适合临时应急。建议先把table_sk和be_tablets都摸一遍因为它们在排查“某个 BE 磁盘特别满”的场景下各有优势。3. 实战SQL一条语句查完所有表的存储占用3.1 最常用的清单SQL下面这条 SQL 是我现在排查容量问题时最先跑的一条它把表名、数据库名、总大小、总行数、副本数一次拉齐SELECT t.TABLE_SCHEMA AS db_name, t.TABLE_NAME AS table_name, ROUND(SUM(s.DATA_SIZE) / 1024 / 1024 / 1024, 2) AS size_gb, SUM(s.NUM_ROWS) AS total_rows, COUNT(DISTINCT s.TABLET_ID) AS tablet_count, MAX(t.REPLICATION_NUM) AS replica_num FROM information_schema.table_sk s JOIN information_schema.tables_config t ON s.TABLE_ID t.TABLE_ID GROUP BY t.TABLE_SCHEMA, t.TABLE_NAME ORDER BY size_gb DESC LIMIT 50;输出结果大致长这样db_nametable_namesize_gbtotal_rowstablet_countreplica_numdwdads_order_detail128.5589012345483dwddwd_user_login_log87.30330012345363adsapp_user_portrait45.125678210243这个结果里的size_gb是单副本大小要估算真实磁盘占用要乘以replica_num默认 3。比如第一行ads_order_detail单副本约 128.55 GB实际占用的物理空间约为 128.55 × 3 ≈ 385.65 GB。3.2 看懂返回结果单位、版本、副本这些细节很多人第一次跑完这条 SQL会有几个疑问DATA_SIZE 的单位是字节所以我在 SQL 里做了三次除以 1024 的换算得到 GB。如果你只除以一次算出来的是 KB容易误判数量级。DATA_SIZE汇总的是当前所有存活版本的文件大小。StarRocks 的每次导入会产生新的 Rowset 版本老版本要等 Compaction 合并后才释放。如果你刚导入完大批量数据立刻查表大小看到的值可能偏大因为版本还没合并完。这不是系统表统计错而是 Compaction 还没做完。NUM_ROWS是所有 Tablet 行数的累加值。对于主键表如果删除操作很多磁盘上可能还残留旧版本的删除标记所以会出现“行数不大、占用却不小”的情况具体原因后面单独讲。3.3 行数和大小对不上大概率是这些原因我遇到过几次诡异情况一张表只有几万行但 size_gb 显示好几十 G。排查下来主要有三类原因主键表的小批量高频更新。每次更新都会产生新的版本文件旧版本数据在 Compaction 之前不会立即清理。高频更新的表版本文件堆积起来体积可能远超实际有效数据。导入时生成了大量小文件。如果你用 Stream Load 频繁写入每个批次都会产生新的 Rowset不给系统合并的时间就会有很多零碎文件占空间。表结构里的字段有大字段。比如 String 类型存了几 KB 的大文本行数不多但单个 Row 体积大放大到 Tablet 级别就非常可观。遇到这类问题不要直接怀疑系统表统计错误先检查表的 Compaction 状态和最近写入频率通常能找到原因。4. 进阶玩法按库、分区、BE 节点多维度盘容量4.1 按数据库维度统计表级清单适合定位“哪张表最大”但如果整个库都占空间很大你还需要一个库维度的汇总视图。把前面那条 SQL 的 GROUP BY 改成TABLE_SCHEMA就行SELECT t.TABLE_SCHEMA AS db_name, ROUND(SUM(s.DATA_SIZE) / 1024 / 1024 / 1024, 2) AS size_gb, SUM(s.NUM_ROWS) AS total_rows, COUNT(DISTINCT t.TABLE_NAME) AS table_cnt, MAX(t.REPLICATION_NUM) AS replica_num FROM information_schema.table_sk s JOIN information_schema.tables_config t ON s.TABLE_ID t.TABLE_ID GROUP BY t.TABLE_SCHEMA ORDER BY size_gb DESC;这个视图的价值在于“治理优先级”。如果某个库占用了全集群 60% 的空间那容量治理的重点就该放在这个库的业务表上。我在实际运维中会把这条 SQL 的结果存成历史快照每周对比一次看哪个库增长最猛再往下钻取表级明细。4.2 按分区粒度找“时间黑洞”表级统计只能告诉你哪张表大不能告诉你是哪个时间段的数据占了大头。对于日志类分区表你需要的其实是“哪个分区最大”。改一下 GROUP BY 条件把PARTITION_ID加进来SELECT t.TABLE_SCHEMA, t.TABLE_NAME, s.PARTITION_ID, ROUND(SUM(s.DATA_SIZE) / 1024 / 1024 / 1024, 2) AS size_gb, SUM(s.NUM_ROWS) AS total_rows FROM information_schema.table_sk s JOIN information_schema.tables_config t ON s.TABLE_ID t.TABLE_ID WHERE t.TABLE_NAME dwd_user_login_log GROUP BY t.TABLE_SCHEMA, t.TABLE_NAME, s.PARTITION_ID ORDER BY size_gb DESC LIMIT 30;这样能快速定位到“最近三个月数据占 80% 空间”这种典型问题。找到之后就可以针对性地给分区设置生命周期或者直接把历史大分区做冷备归档。分区维度的统计是最适合做数据治理的视角。4.3 用 be_tablets 定位 BE 上的热点 Tablet存储分布不均也是常见问题——集群整体容量够但某个 BE 磁盘快满了。这时候要看be_tablets它比table_sk多了 BE 节点维度SELECT BE_ID, ROUND(SUM(DATA_SIZE) / 1024 / 1024 / 1024, 2) AS size_gb, COUNT(*) AS tablet_cnt FROM information_schema.be_tablets GROUP BY BE_ID ORDER BY size_gb DESC;如果发现某个 BE 的数据量远超其他节点可以再往下钻取看这个 BE 上都有哪些大 TabletSELECT BE_ID, TABLET_ID, ROUND(DATA_SIZE / 1024 / 1024, 2) AS size_mb FROM information_schema.be_tablets WHERE BE_ID 你的BE_ID ORDER BY size_mb DESC LIMIT 20;定位到热点 Tablet 之后可以借助 StarRocks 的 Tablet 均衡机制或者手动调整分桶策略把压力分摊开。这个排障思路是常规监控面板给不了的。4.4 算集群“真实物理占用”的正确姿势如果老板问“咱们集群数据量多大”你不能拿单副本大小糊弄过去。真实物理占用要考虑两点副本数和压缩率。如果系统表返回的 DATA_SIZE 已经是压缩后的单副本大小那么集群物理占用 ≈ SUM(单副本DATA_SIZE) × 平均副本数举例说明假设table_sk汇总后所有表单副本大小合计 500 GB默认副本数 3那么集群实际数据文件占用约 1500 GB。如果集群里还开了多副本迁移、或者存在副本不均衡的情况这个数字会有轻微浮动但作为容量估算已经足够精准。如果你想知道“导入前的原始数据量”那就得再乘上压缩倍数。LZ4 压缩倍率取决于数据类型数值型字段压缩率低字符串字段压缩率高通常可以按 2 到 5 倍估算但这不是一个稳定的系数我建议不要过于依赖这个估算日常容量管理以单副本 × 副本数为准。5. 常见问题与排查技巧实录5.1 删了数据容量为什么没降这是最高频的问题。你在业务上 DELETE 了很多行甚至 DROP 了分区但查下来容量一点没少。原因在于 StarRocks 的存储模型。在明细表和聚合表中DELETE 操作通常不是物理删除而是生成删除条件标记真正释放空间要等 Compaction。主键表虽然支持真正的点查删除但旧版本的删除标记也要等合并后才会清理。所以删除后立刻查容量数字自然不会明显下降。实操建议如果是整个分区过期直接用DROP PARTITION不要用 DELETE 逐行删。如果是全表清空用TRUNCATE TABLE它会直接重新创建 Tablet释放最干净。如果是大量条件删除删除后等待 Compaction 完成再观察容量变化。5.2 表显示 0 行存储却占几个 G这种情况我排查过好几次几乎都出现在主键表上。主键表为了保证实时更新能力会保存每个主键对应的删除位图和旧版本数据。业务上把行更新成“逻辑删除”但主键索引还在旧版本数据也没有立即清理因此存储占用降不下来。另外还有一种可能你 SELECT COUNT(*) 查的是最新版本的有效行数而table_sk里的 NUM_ROWS 统计的是所有版本的行数累加。如果导入历史版本只被部分合并就会出现“统计行数远大于实际可见行数”的反差。这类表如果要彻底瘦身建议重建表并重新导入数据或者对表执行一次大版本 Compaction等它完成后空间会明显回落。5.3 副本数调整后统计口径又变了还有一个很容易混淆的点。如果你用ALTER TABLE ... SET REPLICATION_NUM调整过副本数那么系统表返回的单副本大小不变但集群实际占用会相应变化。比如原来 3 副本每表 100 GB调整成 2 副本后物理占用从 300 GB 降到 200 GB。查系统表看到的还是单副本 100 GB所以要结合tables_config.REPLICATION_NUM来动态计算实际占用而不是单纯看 DATA_SIZE。副本调整时要注意降低副本数会立即触发 BE 上的副本删除任务期间磁盘 IO 会有波动增加副本数则会触发跨节点复制会占用网络带宽和磁盘写入。建议在业务低峰期操作。5.4 用 Python 脚本做定时容量巡检手动跑 SQL 只能解决一时之急。我后来写了一个简单的 Python 脚本用 pymysql 直连 FE 的查询端口定时执行前面那几条统计 SQL把结果写到监控表里再用看板展示趋势import pymysql import datetime conn pymysql.connect( hostfe_host, port9030, usermonitor_user, password******, databaseinformation_schema ) sql SELECT t.TABLE_SCHEMA AS db_name, t.TABLE_NAME AS table_name, ROUND(SUM(s.DATA_SIZE) / 1024 / 1024 / 1024, 2) AS size_gb, SUM(s.NUM_ROWS) AS total_rows, MAX(t.REPLICATION_NUM) AS replica_num FROM table_sk s JOIN tables_config t ON s.TABLE_ID t.TABLE_ID GROUP BY t.TABLE_SCHEMA, t.TABLE_NAME ORDER BY size_gb DESC cur conn.cursor() cur.execute(sql) rows cur.fetchall() for row in rows: db_name, table_name, size_gb, total_rows, replica_num row physical_gb round(size_gb * replica_num, 2) print(f{datetime.datetime.now()} | {db_name}.{table_name} | f单副本: {size_gb} GB | 物理占用: {physical_gb} GB | 行数: {total_rows}) cur.close() conn.close()脚本本身不复杂关键是把“每天跑一遍”“数据落库”“对比环比”这三件事固定下来。容量问题最怕的不是突然爆掉而是缓慢增长到临界点你才发现。定时巡检就是用来提前暴露趋势的。6. 日常存储治理的几条实操建议6.1 给表设生命周期别裸奔日志类、行为类数据表一定要在建表时就规划好生命周期。StarRocks 支持通过动态分区特性管理过期数据你可以设置保留最近 N 天的分区系统会自动创建新分区、淘汰过期分区。别等到磁盘满了再手工 DROP那是被动救火建表时多想一步才是正经。实操上可以按天分区设置dynamic_partition.enable true、dynamic_partition.start -7保留最近一周的数据。这样存储增长是可控的查容量时也能通过分区维度轻松定位到时间范围。6.2 数据模型和分桶数影响存储效率我在排查中发现很多表的存储膨胀和分桶设置不合理有关。分桶数过多、桶内数据太少会产生大量空 Tablet每个 Tablet 都有元数据和索引开销分桶数过少、桶内数据太多又会导致单次查询扫描数据量过大影响并发性能。建表时根据数据规模选分桶数一般建议每个 Tablet 的数据量在几百 MB 到 1 GB 左右。有些表从几千万行涨到了几十亿行最初的分桶设计早就过时了这时候不要硬扛可以考虑重新设计分桶并迁移数据存储和查询性能都会有明显改善。6.3 大数据量导入时的注意事项如果你经常使用 Stream Load 导入数据我有个实在建议合理控制批次大小不要一次导入太小批。大批量高频的小文件导入会让每个 Tablet 的版本数快速膨胀版本多了 Compaction 压力大存储统计也会短暂虚高。更合理的做法是攒批导入比如每 5 分钟或者每 500 MB 一个批次让每次导入的数据量相对均衡。这样既不影响实时性又能给 Compaction 留出足够的时间存储占用和查询性能都会更稳定。6.4 把容量统计融入日常运维最后想分享的一个运维习惯是每次排查完存储问题之后把用过的 SQL 沉淀下来做成一个“容量巡检四件套”——全表容量 Top 50、全库容量汇总、分区热点 Top 20、BE 节点分布。这四张表组合起来基本能应对 90% 的容量分析场景。配套的还有告警规则。除了监控集群总容量建议对单表增量也做告警比如某张表一周内体积增长超过 50%就触发提醒。这样能在业务异常写入时第一时间发现而不是等到磁盘告警才回头查表。说实话查表存储占用本身不难难的是把“查出来的数字”和“真实的存储模型”对应起来。我刚开始用系统表的时候也走过弯路拿单副本大小乘错倍数、拿带副本数的统计当原始数据大小这些坑躲过一次之后后面就顺畅了。建议你拿到本文的 SQL 后先在测试环境跑一遍对照集群面板的实际数据核对一下口径再拿到生产环境用。熟悉之后这张表就是你的容量管理底牌。
网站建设高端定制企业官网