StarRocks表存储占用排查:元数据查询与分区Tablet下钻实战
发布时间:2026/9/30 4:58:50来源:尧图网络
周五下午集群告警弹了出来BE磁盘使用率超过90%。这种时候最烦人的不是扩容本身而是你根本不知道哪些表在吃空间。我先扫了一圈Top级大表才发现一张两年前的点击流日志表占了整个集群将近三分之一的存储。后来把历史分区一清磁盘使用率直接降了二十个点。从那次以后“每张表到底占多少存储”就成了我每周必看的数据。在StarRocks里这个问题没有想象中那么简单。表的数据不是整块存在一个文件里的而是按“表 → 分区 → 分桶Tablet → 行集Rowset”层层拆分每一层都会影响你最终看到的“大小”口径。再加上列式存储、压缩算法、副本数这些因素“一张表占多少存储”可以被解读出至少三种含义。这篇就围绕怎么查看每张表的存储占用把常用的查询入口、脚本、以及几个容易翻车的坑一次性说清楚。1. 动手前先理清口径StarRocks表大小的三种含义1.1 逻辑行数、物理压缩与“DATA_LENGTH”的关系StarRocks是典型的列式存储数据库每个Tablet内部的数据按列独立编码、独立压缩。我们通过SQL查到的元数据大小字段比如DATA_LENGTH或DATA_SIZE单位是字节通常指的是落盘后的物理大小而不是导入时的原始数据量。举例来说一张表有1亿行每个字段加起来可能逻辑上有20GB但经过列式编码和LZ4压缩后物理文件可能只有3GB。这就是为什么很多刚接触StarRocks的同学看到表行数很大、大小却很小会误以为查询口径有问题。实际上逻辑大小和物理大小本来就不是一回事。查询元数据字段时需要先确认你当前版本的信息模式表里大小列到底叫什么名字。不同版本有差异有的暴露为DATA_LENGTH有的叫DATA_SIZE。推荐先执行一条确认语句DESC information_schema.tables;看完输出列名再写查询避免SQL直接报“Unknown column”的错。这个习惯虽然基础但能省去很多不必要的排查时间。1.2 副本数带来的“物理翻倍”StarRocks为了保证高可用每份分桶数据默认会有多个副本通常是3副本。也就是说一张表如果单副本物理大小是1GB那么它在整个集群里实际占用的磁盘就是3GB而且这3GB分散在三台BE节点上。很多人查完DATA_LENGTH之后觉得不对劲——“怎么会比BE磁盘上统计的小这么多”十有八九是没把副本数乘进去。建表时的replication_num属性决定了这个翻倍的系数默认值通常为3。如果你们集群做过缩副本、跨机房双副本等调整实际结果要按真实配置来算。1.3 索引、元数据与碎片的额外开销数据文件只是存储占用的一部分。主键模型Primary Key表需要在BE端维护主键索引这部分占用不会完整反映在DATA_LENGTH里高频写入造成的Rowset碎片、待合并的临时数据也会在BE磁盘上形成额外开销。再加上FE的元数据镜像、审计日志等最终BE节点的真实磁盘使用量通常会比“所有表DATA_LENGTH乘以副本数”的总和高出几个百分点。这也是为什么我习惯把查看表占用的工作分成两层一层是从StarRocks元数据拿“逻辑物理大小”另一层是登录BE节点用du命令核对真实磁盘占用。两层对得上说明集群健康对不上就要留意索引开销、碎片或者副本迁移中的临时占用。2. 查看单张表与全库表大小的主流方法2.1 通过 information_schema.tables 一键总览最方便的方式还是走MySQL协议查信息模式表。StarRocks兼容了MySQL的information_schema我们可以直接用SQL把全集群所有库表的大小和行数拉出来。不同版本的列名略有差异我先按最常见的字段写法给一个模板SELECT table_schema, table_name, table_rows, data_length / 1024 / 1024 / 1024 AS size_gb FROM information_schema.tables WHERE table_schema NOT IN (__internal__, information_schema, starrocks) ORDER BY data_length DESC LIMIT 20;这个查询可以直接看出哪张表最大、哪个库最占空间。需要注意两点一是table_schema过滤条件必须把系统库排除掉否则你会看到一堆内部表二是这个data_length一般是单副本大小不是集群真实总占用。如果想看某个具体库或某张具体表只需要加条件SELECT table_name, table_rows, ROUND(data_length / 1024 / 1024, 2) AS size_mb FROM information_schema.tables WHERE table_schema your_db AND table_name your_table;如果查询报字段不存在先跑一下DESC information_schema.tables;把data_length替换成你环境里实际的大小字段比如data_size逻辑是一样的。2.2 通过 SHOW DATA 快速粗查除了信息模式表StarRocks还保留了SHOW DATA系列命令适合交互式场景快速查看-- 查看当前默认库下所有表的大小 SHOW DATA; -- 查看指定表的单副本大小与行数 SHOW DATA FROM your_db.your_table;这个命令的输出列在不同版本略有区别但核心信息都包含表名、数据大小和行数。它的优势是免去了记忆字段名的成本劣势是输出不够灵活不方便排序和过滤写自动化脚本时还是建议用SQL方式。2.3 通过 SHOW PARTITIONS 定位大分区如果一张表非常大通常不是所有分区的数据量都均匀。以日期分区的日志表为例最近一个月的数据往往占大头历史冷分区虽然多加起来可能反而比例不大。用分区级命令可以精准定位SHOW PARTITIONS FROM your_db.your_table;输出结果里重点关注PartitionName、DataSize、RowCount这几列单位通常是字节。这样就能迅速判断哪个分区最占空间再决定是清理、归档还是做冷热分层。对自动化运维来说可以把分区大小查询做成脚本勾出Top 10大分区配合动态分区策略优化历史数据生命周期。2.4 通过 SHOW TABLET 下钻到分桶粒度如果表大小没问题但你发现某个BE节点的磁盘使用率明显高于其他节点可能是数据倾斜。这时候需要下钻到分桶粒度检查。SHOW TABLET FROM your_db.your_table;这条命令会列出表的所有Tablet信息重点看TabletId、Size、RowCount。如果某个Tablet的Size明显高于其他Tablet说明分桶键选择有问题导致数据分布不均。倾斜严重的表光靠扩容解决不了需要重新设计分桶字段和分桶数。再往下你还可以用SHOW TABLET 12345678;查看单个Tablet的详细信息包括它分布在哪些BE节点、副本状态是否健康。这种粒度的排查在集群容量管理和数据均衡调优时非常有用。3. 实战快速定位Top N大表并核算集群真实占用3.1 一条SQL找出前20大表现在进入实际场景。假设你的BE磁盘告警第一步就是要拿到一张表级别的存储排行。我会直接用信息模式表查Top 20SELECT table_schema, table_name, table_rows, ROUND(data_length / 1024 / 1024 / 1024, 2) AS single_replica_gb, ROUND(table_rows / 10000.0, 2) AS rows_wan FROM information_schema.tables WHERE table_schema NOT IN (__internal__, information_schema, starrocks) ORDER BY data_length DESC LIMIT 20;结果里single_replica_gb表示单副本物理大小rows_wan表示以“万”为单位的行数。拿到这张榜单后通常能很快锁定三四个重点目标。我习惯把这条SQL的结果和业务方对一下为什么这张表这么大是数据量正常增长还是存在无效写入、缺少清理策略很多时候一张每天写入上亿行的明细日志表只要保留周期从永久改为30天存储压力就能缓解一半。3.2 确认副本数计算真实磁盘占用前面说过元数据里的大小不包含副本。要算集群真实占用必须拿到每张表的replication_num。最简单的方法是看建表语句SHOW CREATE TABLE your_db.your_table;输出里的PROPERTIES段落会包含replication_num。如果是统一默认配置可以查FE参数里的默认副本数或者直接问DBA确认。拿到副本数后真实占用就是单副本大小乘以副本数。如果表很多懒得一张张看建表语句可以按库统一估算SELECT table_schema, ROUND(SUM(data_length) * 3 / 1024 / 1024 / 1024, 2) AS approx_cluster_gb FROM information_schema.tables WHERE table_schema NOT IN (__internal__, information_schema, starrocks) GROUP BY table_schema ORDER BY approx_cluster_gb DESC;这里直接用3作为副本系数前提是你的集群确实是3副本。如果你不确定先把样例表的结果和du统计对比一下确定系数后再批量估算。3.3 结合行数与压缩率判断“该不该优化”只看大小还不够我会把行数也拉出来算一个“单行平均物理大小”SELECT table_schema, table_name, table_rows, data_length, ROUND(data_length / NULLIF(table_rows, 0), 2) AS avg_bytes_per_row FROM information_schema.tables WHERE table_rows 0 AND table_schema NOT IN (__internal__, information_schema, starrocks) ORDER BY avg_bytes_per_row DESC LIMIT 20;单行平均物理大小可以快速区分两类问题如果行数很大、但单行平均很小说明压缩效果很好属于正常的大表如果行数不大、单行平均却很高就要看看是不是有超宽字段、高基数列或者未压缩的数据类型。这张表让我想起一个经典案例某个业务表只有几千万行但占了几百GB查下来发现里面有大量的长字符串字段而且很多是重复内容。后来调整了编码方式空间立刻省了一大半。所以“大表”不等于“行多”也可能是“行宽”或“压缩率低”。3.4 把例行检查固化成每日增长监控一次性的查询解决不了长期问题。我更推荐做一个“存储快照表”每天定时把各表大小、行数、分区数存入一个管理库形成历史趋势。CREATE DATABASE IF NOT EXISTS ops_monitor; CREATE TABLE IF NOT EXISTS ops_monitor.table_size_snapshot ( dt DATE, table_schema VARCHAR(64), table_name VARCHAR(64), table_rows BIGINT, data_length_bytes BIGINT, replica_num TINYINT ) ENGINE OLAP DUPLICATE KEY(dt, table_schema, table_name) PARTITION BY RANGE(dt)( START (2024-01-01) END (2030-12-31) EVERY (INTERVAL 1 DAY) ) DISTRIBUTED BY HASH(table_schema, table_name) BUCKETS 10 PROPERTIES (replication_num 1);然后每天用一条INSERT INTO ... SELECT把快照写入INSERT INTO ops_monitor.table_size_snapshot SELECT CURDATE() AS dt, table_schema, table_name, table_rows, data_length AS data_length_bytes, 3 AS replica_num FROM information_schema.tables WHERE table_schema NOT IN (__internal__, information_schema, starrocks);有了历史数据就可以写趋势SQL找出“近7天增长最快”的表SELECT t2.table_schema, t2.table_name, t2.data_length_bytes - t1.data_length_bytes AS delta_bytes FROM ops_monitor.table_size_snapshot t1 JOIN ops_monitor.table_size_snapshot t2 ON t1.table_schema t2.table_schema AND t1.table_name t2.table_name AND t1.dt DATE_SUB(CURDATE(), INTERVAL 1 DAY) AND t2.dt CURDATE() ORDER BY delta_bytes DESC LIMIT 20;这个思路把“查一下现在谁最大”升级成了“持续观察谁在变胖”对于容量规划的意义完全不同。4. 常见问题与排查技巧实录4.1 DATA_LENGTH为0或明显偏小查询结果里某些表DATA_LENGTH是0不代表它没数据。常见原因有三个表刚创建还没有写入数据还在导入过程中尚未生成可查询的元数据统计或者表的Tablet处于异常状态副本缺失、克隆中。遇到0值表先用SHOW TABLET FROM 库名.表名;确认Tablet状态再看是否有副本在恢复。还有一类情况是数据已经写入、分区也显示有RowCount但大小字段迟迟没更新。StarRocks的元数据统计有一定刷新周期不是写入后立刻精确反映每个字节尤其是高并发小批量导入时很多Rowset处在待合并状态。我的经验是以实际查询能扫到的分区大小为准配合BE磁盘统计做双保险不要只看一个数字。4.2 结果和BE磁盘统计对不上我前面提到的“元数据大小”和“真实磁盘占用”对不上属于正常现象。但偏差过大就要警惕了。最直接的核对方式是在BE节点上统计实际文件大小。假设你要核对某张表在BE上的真实占用流程是这样的# 先查这张表有哪些tablet mysql -h FE_HOST -P 9030 -e SHOW TABLET FROM your_db.your_table; # 在BE节点上按tablet_id统计目录大小 du -c --block-sizeG /data/be/storage/data/tablet_id_1 \ /data/be/storage/data/tablet_id_2 \ ...注意BE的存储路径一定要和你集群实际配置的storage_root_path一致。如果这张表有多副本分布在多台BE上需要分别到每台BE上统计再累加得到的结果才是真实集群占用。如果物理统计比元数据统计大很多通常有小文件碎片、未合并的Rowset或者主键索引占用。如果物理统计比元数据统计小那就需要检查是不是有副本缺失未恢复或者数据目录做了软链接、多层路径导致统计遗漏。4.3 系统库表混入统计新手最容易犯的错就是全量查information_schema.tables时把系统库的表也统计进去。StarRocks内置的__internal__库里有很多系统内部表starrocks库新版本存放统计信息、资源信息等元数据这些都会干扰容量评估。所以我的集群巡检SQL永远会在WHERE条件里带上这三类过滤WHERE table_schema NOT IN (__internal__, information_schema, starrocks)别忘了还有用户自己建的临时库、ETL中间库这些可能也需要根据业务情况排除。把过滤条件固化到脚本里就不会每次手敲。4.4 数据倾斜导致单BE磁盘爆炸有时候表的总大小正常但某个BE节点还是报警。这种情况优先考虑数据倾斜。我用两个办法快速验证第一个办法是看单表的Tablet分布SHOW TABLET FROM your_db.your_table;如果某个Tablet的数据量是其他的好几倍说明分桶键选择不合理热点全打在一个桶上。第二个办法是直接在BE上扫目录大小排行du -s /data/be/storage/data/* | sort -rn | head -30看到最大的几个目录再反查tablet_id归属哪个表就能定位到倾斜目标。我处理过一次典型的倾斜案表的分布键选了性别字段男女性别各占一半但业务写入却有几百倍的偏差。后来把分桶键改成用户ID数据立刻均衡了。4.5 查询性能与元数据刷新延迟information_schema.tables看着像一张普通表实际是StarRocks动态生成的元数据视图。当集群表数量多、分区数量大时全量扫描这个视图可能会比较慢甚至会放大FE的元数据压力。所以我一般建议能按库过滤就不要全集群扫能按表过滤就不要扫整个库。比如明确知道嫌疑库是ods_log就先把这个库单独拎出来查SELECT table_name, data_length / 1024 / 1024 AS size_mb FROM information_schema.tables WHERE table_schema ods_log ORDER BY size_mb DESC;另外这类信息模式查询不适合放到高频热路径里反复执行。我通常是每天固定时间跑一次快照任务而不是每次要看都实时扫一遍。低频、聚合、留痕才是容量监控的正确姿势。再补充一点如果你发现某个表的分区特别多比如几千个分区SHOW PARTITIONS的输出会非常长甚至把客户端刷屏。这时候可以用脚本或LIMIT配合条件过滤也可以直接改查information_schema中对应的分区级视图尽量缩小范围再处理。最后分享一点个人经验我做了几年StarRocks集群运维最大的感受是看表大小这件小事背后真正考验的是对存储体系的理解。只知道跑一条SQL远远不够你还要明白DATA_LENGTH是什么口径、副本怎么翻倍、压缩率如何影响判断。遇到线上问题先冷静确认口径再做定论能少走很多弯路。最后分享一个小技巧我习惯在每次大版本升级之后重新核对一次information_schema.tables里的大小字段类型和输出列因为StarRocks迭代很快元数据字段偶有调整。提前确认好就不会在升级后的第一个巡检日被打个措手不及。
网站建设高端定制企业官网