StarRocks SQL 常见问题全解:从查询缓存、排序稳定性到崩溃与内存排障实战
【免费下载链接】starrocksThe world's fastest open query engine for sub-second analytics both on and off the data lakehouse. With the flexibility to support nearly any scenario, StarRocks provides best-in-class performance for multi-dimensional analytics, real-time analytics, and ad-hoc queries. A Linux Foundation project.项目地址: https://gitcode.com/GitHub_Trending/st/starrocks
StarRocks 是 Linux 基金会旗下的开源 MPP 分析型数据库,通过 MySQL 协议对外提供 SQL 查询能力。本文基于官方 FAQ 文档 Sql_faq 整理并深入扩充:覆盖查询缓存机制、NULL 与浮点运算陷阱、分布式排序稳定性、Hive/ES 外表报错、DDL 阻塞、查询并发与 Hint 控制、BE 崩溃现场收集、内存超限排障等高频 SQL 问题,并结合仓库源码(FE 会话变量、BE 内存追踪器、brpc 连接配置等)印证每个结论的底层实现,读完你可以独立处理 StarRocks 生产环境中的绝大多数 SQL 疑难杂症。
一、查询结果缓存:StarRocks 如何加速重复查询
StarRocks 不直接缓存最终查询结果。从 v2.5 起,StarRocks 通过 Query Cache 特性将第一阶段聚合的中间结果存入缓存:与历史查询语义等价的新查询可以复用已缓存的计算结果来加速。Query Cache 消耗的是 BE 内存,详细说明见 Query cache。
这一点在排障时有实际意义:当某些复杂查询行为异常时,可以通过关闭查询缓存来排除其干扰:
set enable_query_cache = false;二、语义类问题:NULL、DECODE 与 utf8mb4
NULL 参与计算:标准 SQL 规定,任何包含
NULL操作数的计算都返回NULL,唯一例外是ISNULL()这类专门判断 NULL 的函数。写谓词时应显式使用IS NULL/COALESCE处理空值分支。DECODE 函数:StarRocks 不支持 Oracle 的
DECODE,但其兼容 MySQL 语义,可直接使用CASE WHEN语句替代:SELECT CASE WHEN status = 1 THEN 'active' ELSE 'inactive' END FROM t;utf8mb4 字符:存储在 StarRocks 中的 utf8mb4 字符不会截断或乱码,可直接存中文、emoji 等多字节字符。
三、主键表数据可见性与 VARCHAR 长度
主键表(Primary Key table)加载完成后能立即查到最新数据。StarRocks 参考 Google Mesa 的思路做数据合并,由 BE 触发 merge,共两类 compaction;即使合并尚未完成,查询过程中也会等待/完成所需合并,因此加载后即可读到最新数据。
VARCHAR 定最大长度是否影响存储?不影响。VARCHAR 是变长类型,按实际数据长度存储,创建表时指定不同的 varchar 长度对同一份数据的查询性能影响极小,无需纠结长度取值。
四、DDL 阻塞与 Colocate 副本数修改
4.1 "table's state is not normal":alter table 报错
该错误说明上一次 alter 尚未完成。可以检查此前变更的状态:
show tablet from lineitem where State="ALTER";变更耗时与数据量成正比,一般数分钟内完成。建议在变更表期间暂停数据导入,因为导入会降低变更完成速度。
4.2 Colocate 表无法修改副本数
报错table *** is colocate table, cannot change replicationNum的原因是:创建 colocate 表时必须设置group属性,因此不能对单表修改副本数。正确做法是对组内所有表统一操作:
- 将组内所有表的
group_with设置为empty; - 为组内所有表设置合适的
replication_num; - 将
group_with恢复为原值。
4.3 "create partititon timeout":truncate 表报错
Truncate 表需要创建对应分区再交换,分区数量多时容易超时;此外大量导入任务会让 compaction 期间长期持锁,建表时拿不到锁。导入任务过多时,可在be.conf中将tablet_map_shard_size设置为512以降低锁竞争。
从源码结构看,该参数默认值为1024(见 be/src/common/config.h#L1097-L1098),注释中给出的经验公式为tablet_map_shard_size = total_num_of_tablets_in_BE / 512,即 BE 上 tablet 总数越多,可适度调大该分片数来平衡锁粒度与内存占用。
4.4 查看 DDL 执行进度
查看默认数据库下所有列变更任务:
SHOW ALTER TABLE COLUMN;查看某张表最近一次列变更任务:
SHOW ALTER TABLE COLUMN WHERE TableName="table1" ORDER BY CreateTime DESC LIMIT 1;五、外表查询报错:Hive 元数据与 Kerberos
5.1 "get hive partition meta data failed: java.net.UnknownHostException:hadooptest"
原因是无法获取 Hive 分区的元数据。解决方法:将core-site.xml和hdfs-site.xml中的配置拷贝到fe.conf和be.conf中。仓库内 conf/hadoop_env.sh 即 FE/BE 访问 Hadoop 生态的配套环境脚本。
5.2 "Failed to specify server's Kerberos principal name"
访问带 Kerberos 认证的 Hive 外表时出现此错误,需在fe.conf与be.conf的hdfs-site.xml配置段中加入:
<property> <name>dfs.namenode.kerberos.principal.pattern</name> <value>*</value> </property>5.3 Elasticsearch 动态映射导致长文本列查不出
当 ES 使用动态映射且字段字符串长度超过 256 时,其类型为:
"k4": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }StarRocks 会按keyword类型转换查询语句,而keyword长度超过 256(ignore_above限制)后该列无法被查询。解决方案是移除fields中的keyword子映射,改用text类型。
六、优化器与 FE 侧排障
6.1 "planner use long time 3000 remaining task num 1"
该错误通常由 Java 进程 Full GC 引起,可通过 BE 监控和fe.gc.log确认。两种缓解手段:
- 让 SQL 客户端同时访问多个 FE,分散负载;
- 将 JVM 堆大小在
fe.conf中从 8 GB 调到 16 GB,减少 Full GC 影响。
6.2 "StarRocks planner use long time xxx ms in logical phase"
- 分析
fe.gc.log,确认是否有 Full GC; - 若 SQL 执行计划确实复杂(多表 join、多层子查询),可增大优化超时时间
new_planner_optimize_timeout(单位 ms)。该变量在 FE 会话变量中定义,见 SessionVariable.java#L491:
set global new_planner_optimize_timeout = 6000;6.3 Unknown Error 的逐项排除法
遇到 Unknown Error 时,可逐个尝试以下开关后再执行 SQL,定位问题优化器特性:
set disable_join_reorder = true; set enable_global_runtime_filter = false; set enable_query_cache = false; set cbo_enable_low_cardinality_optimize = false;随后收集EXPLAIN COSTS、EXPLAIN VERBOSE、PROFILE 和 Query Dump(见第七节)提供给支持团队。
6.4 高并发下资源正常但 SQL 变慢
原因通常是网络或 RPC 延迟。可将 BE 参数brpc_connection_type调整为pooled后重启 BE。源码印证:该参数在 be/src/common/config.h#L1078 定义为枚举single,pooled,short,默认single,并在 internal_service_recoverable_stub.cpp#L69 等处被赋给 brpc 通道的options.connection_type,直接影响 FE→BE 内部 RPC 的建连方式。
七、SQL 排障信息收集标准流程
进行 SQL 优化或排障时,建议收集以下四类信息:
EXPLAIN COSTS <SQL>(包含统计信息)EXPLAIN VERBOSE <SQL>(包含数据类型、nullable、优化策略)- Query Profile(通过 FE Web 界面
http://<fe_ip>:<fe_http_port>的 Queries Tab 查看) - Query Dump(通过 HTTP API 获取)
wget --user=${username} --password=${password} --post-file ${query_file} http://${fe_host}:${fe_http_port}/api/query_dump?db=${database} -O ${dump_file}该 API 在 FE 中由 QueryDumpAction.java 实现(POST /api/query_dump?db=test,post_data 为查询语句)。Query Dump 包含:查询语句、涉及的表 schema、会话变量、BE 数量、统计信息(Min/Max)、异常信息(异常栈)。FE 单元测试中还维护了丰富的 query_dump 回放样例(如 ssb10.json),可用于回归验证优化器行为。
八、BE 崩溃时的现场收集
- 根据
be.out的报错栈找到导致崩溃的query_id; - 用
query_id在fe.audit.log中定位对应的 SQL。
需要收集并提交的信息:
be.out日志- 执行 SQL 时的
pstack $be_pid > pstack.log输出 - Core Dump 文件
收集 Core 文件步骤:
获取对应 BE 进程:
ps aux| grep be将 Core 文件大小上限设为 unlimited:
prlimit -p $bePID --core=unlimited:unlimited并验证上限确实为 unlimited:
cat /proc/$bePID/limits
若该项不是0,进程崩溃时会在 BE 部署根目录生成 Core 文件。
九、内存超限错误的三种场景与排查
源码 be/src/runtime/mem_tracker.cpp#L246-L274 中定义了多档内存超限报错,与 FAQ 列出的三种场景一一对应:
- 单查询内存超限:报错
Mem usage has exceed the limit of single query, You can change the limit by set session variable exec_mem_limit.,解决:调整会话变量exec_mem_limit(FE 中定义于 SessionVariable.java#L214); - 查询池内存超限:报错
Mem usage has exceed the limit of query pool,解决:优化 SQL 本身; - BE 总内存超限:报错
Mem usage has exceed the limit of BE,解决:分析内存占用。
内存分析命令(BE 内存追踪器通过 HTTP 页面暴露,见 default_path_handlers.cpp#L341-L343 中/mem_tracker路由):
curl -XGET -s http://BE_IP:BE_HTTP_PORT/metrics | grep "^starrocks_be_.*_mem_bytes\|^starrocks_be_tcmalloc_bytes_in_use" curl -XGET -s http://BE_IP:BE_HTTP_PORT/mem_tracker十、分布式查询的稳定性陷阱
10.1 ORDER BY + LIMIT 结果不一致
当列 A 基数很小时,select B from tbl order by A limit 10每次查询结果可能不同。SQL 只能保证列 A 有序,不能保证列 B 的次序;StarRocks 是分布式数据库,数据按分片分布,多台机器返回的 B 顺序可能不同。解法:
select B from tbl order by A, B limit 10;同理,row_number()多次执行结果不一致也是同一原因:ORDER BY 字段存在重复值时,SQL 标准不保证稳定排序,建议在 ORDER BY 中加入唯一字段(如employee_id)确保稳定。子查询中的 ORDER BY 不生效也是预期行为——外层未指定 ORDER BY 时,分布式执行无法保证全局有序。
10.2 浮点数比较与计算误差
直接用=比较浮点数会因精度误差导致结果不稳定,推荐改用范围检查。FLOAT/DOUBLE 在avg、sum等聚合中存在精度误差;需要高精度时使用 DECIMAL 类型,但性能会下降 2–3 倍,需按业务权衡。
10.3 分区键上使用函数
对分区键使用函数会导致分区裁剪不准确,从而降低查询性能。应尽量让谓词以“列 op 字面量”形式直接落在分区键上。
10.4 分区字段的格式限制
2021-10不是合法日期格式,也不能直接作分区字段;需用函数转换为2021-10-01后再作为分区字段。
10.5 DELETE 语句的限制
DELETE 中的二进制谓词必须是column op literal形式,不支持表达式。例如以下写法会报错:
mysql > DELETE FROM starrocks.ods_sale_branch WHERE create_time >= concat(substr(202201,1,4),'01') and create_time <= concat(substr(202301,1,4),'12'); SQL Error [1064][42000]: Right expr of binary predicate should be value当前没有计划支持表达式作为比较值(如DELETE FROM t WHERE to_days(now())-to_days(publish_time) > 7亦不支持)。
十一、连接、会话与运维操作技巧
保留关键字作列名:如
rank需用反引号转义为`rank`。停止执行中的 SQL:
show processlist;查看正在执行的 SQL,kill <id>;终止对应 SQL;也可通过SHOW PROC '/current_queries';查看与管理。清理空闲连接:通过会话变量
wait_timeout(单位:秒)控制空闲连接超时,MySQL 客户端默认约 8 小时后自动清理。时区:
select now()返回time_zone系统变量指定的时区;FE/BE 日志使用机器本地时区。UNION ALL 并行:UNION ALL 中的多个 SQL 段是并行执行的。
增加 SQL 查询并发:调整会话变量
pipeline_dop。FE 中同时定义了max_pipeline_dop(仅在pipeline_dop=0自动推算时生效的上限),见 SessionVariable.java#L436-L437;自动推算逻辑与 BE 平均核数相关(核数 <2 时取 1,否则取平均核数)。数据倾斜检查:使用
ADMIN SHOW REPLICA DISTRIBUTION FROM <table>查看 tablet 分布。统计信息收集开关:
-- 关闭自动收集 enable_statistic_collect = false; -- 关闭导入触发的收集 enable_statistic_collect_on_first_load = false; -- 升级至 v3.3 及以上版本后手动设置 set global analyze_mv = "";Hint 控制 join 方式:支持
broadcast与shuffleHint:select * from a join [broadcast] b on a.id = b.id; select * from a join [shuffle] b on a.id = b.id;
十二、查询效率与规模类问题
SELECT *与指定列的列效率差距大:先查 Profile 中的 MERGE 细节,重点看存储层聚合是否耗时过长(例如某聚合aggr: 26s270ms、sort: 15s551ms),以及指标列是否过多——对百万行聚合数百列会显著放大开销。- 库内上百张表时的效率:连接 MySQL 客户端时加
-A参数(禁止客户端预读数据库信息):mysql -uroot -h127.0.0.1 -P8867 -A。 - 查看库表大小:使用 SHOW DATA 命令:
SHOW DATA;显示当前库所有表的数据大小与副本数;SHOW DATA FROM <db_name>.<table_name>;显示指定表的数据大小、副本数与行数。
- 降低 BE/FE 日志磁盘占用:调整日志级别及相关参数,参考 BE 参数配置。
小结
本 FAQ 覆盖的问题可归纳为五条主线:语义差异(NULL、浮点、分布式排序)、DDL/副本运维(alter 阻塞、colocate、truncate 锁竞争)、外表集成(Hive 元数据、Kerberos、ES 映射)、优化器与 FE(planner 超时、GC、Unknown Error 排除法)、资源与崩溃排障(内存超限三场景、Core 收集、Query Dump)。每个结论均可在仓库中找到对应实现锚点——FE 侧会话变量集中在 SessionVariable.java,BE 侧内存控制集中在 mem_tracker.cpp,配置项定义集中在 be/src/common/config.h——遇到同类问题时可沿这些入口快速定位源码。
【免费下载链接】starrocksThe world's fastest open query engine for sub-second analytics both on and off the data lakehouse. With the flexibility to support nearly any scenario, StarRocks provides best-in-class performance for multi-dimensional analytics, real-time analytics, and ad-hoc queries. A Linux Foundation project.项目地址: https://gitcode.com/GitHub_Trending/st/starrocks
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考