StarRocks `negative()` 数学函数详解:语法、数据类型支持与向量化实现原理
2026/9/19 3:35:55 网站建设 项目流程

StarRocksnegative()数学函数详解:语法、数据类型支持与向量化实现原理

【免费下载链接】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

negative()是 StarRocks 提供的一元数学函数,用于返回输入参数的相反数(即对数值取负)。本指南以 negative.md 文档为骨架,完整讲解其语法、参数类型、返回值与实操示例,并结合 BE(be/src/exprs/math_functions.h)与 FE(fe/fe-core/src/main/java/com/starrocks/catalog/FunctionSet.java等)的源码实现,深入说明它在向量化执行、DECIMAL 类型推导与统计信息估算中的底层机制。阅读完本文,你将能在 SQL 中正确、高效地使用negative(),并理解它与一元负号运算在优化器层面的联动关系。

函数简介:返回输入参数的相反数

negative(arg)是 StarRocks 数学函数家族中的一元函数,语义等价于对参数执行一元取负运算(-arg),但与直接使用负号不同,它作为显式函数调用,可出现在 SELECT 列表、WHERE 条件、JOIN 关联表达式等任意 SQL 位置,并被 FE 优化器识别为单调递减函数参与表达式推导(详见下文"与优化器的联动"章节)。

该函数是"严格一元函数"(strict unary function)——输入为单个数值,输出与输入保持完全相同的数据类型,不会发生隐式类型转换或精度损失。

语法

negative(arg)

该函数只接受一个参数,返回其相反数。语法形式与 StarRocks 其他一元数学函数(如positive()abs())保持一致。

参数说明与支持的数据类型

arg支持以下六种数值数据类型:

数据类型说明
BIGINT64 位有符号整数
DOUBLE双精度浮点数
DECIMALV2StarRocks 的旧版高精度定点小数类型(最大精度 27,基于int128_t存储)
DECIMAL32定点小数类型,基于 32 位存储(DECIMAL V3 系列)
DECIMAL64定点小数类型,基于 64 位存储(DECIMAL V3 系列)
DECIMAL128定点小数类型,基于 128 位存储(DECIMAL V3 系列)

从参数列表可以看出,negative()的设计刻意覆盖了 StarRocks 的整数(BIGINT)、浮点(DOUBLE)与全部定点小数(DECIMAL 家族)数值类型,使其可以安全地作用于任意数值列而无需提前转换类型。

返回值

返回与输入arg相同数据类型的值,即:

  • 输入为BIGINT,返回BIGINT相反数;
  • 输入为DOUBLE,返回DOUBLE相反数;
  • 输入为DECIMALV2/DECIMAL32/DECIMAL64/DECIMAL128,返回同精度、同小数位的定点小数相反数。

这意味着在使用negative()对定点小数列取负时,不会破坏列的精度与 scale,计算结果可直接写回同类型目标列。

使用示例

以下是官方文档给出的两个典型示例(来自 negative.md)。

示例一:对 BIGINT 取负

mysql> select negative(3); +-------------+ | negative(3) | +-------------+ | -3 | +-------------+ 1 row in set (0.00 sec)

示例二:对 DECIMALV2 取负

mysql> select negative(cast(3.14 as decimalv2)); +--------------------------------------+ | negative(CAST(3.14 AS DECIMAL(9,0))) | +--------------------------------------+ | -3.14 | +--------------------------------------+ 1 row in set (0.01 sec)

第二个示例展示了negative()与 DECIMAL 类型配合的典型用法:先将浮点字面量3.14显式转换为 DECIMAL 类型,再通过negative()得到-3.14,结果完整保留了小数部分。这在实际业务中对应"将金额、单价等定点小数列整体取负(如冲销、退款)"的常见场景。

结合 BE 源码看向量化实现

统一的严格一元函数模板

negative()的 BE 端实现位于 math_functions.h,采用模板化向量化函数定义:

template <LogicalType Type> DEFINE_VECTORIZED_FN(negative) { if constexpr (lt_is_decimal<Type>) { const auto& type = context->get_return_type(); return VectorizedStrictUnaryFunction<negativeImpl>::evaluate<Type>(VECTORIZED_FN_ARGS(0), type.precision, type.scale); } else { return VectorizedStrictUnaryFunction<negativeImpl>::evaluate<Type>(VECTORIZED_FN_ARGS(0)); } }

核心实现逻辑可以拆解为两点:

  1. 向量化批处理:函数通过VectorizedStrictUnaryFunction模板对整列数据(Column)进行批量运算,而不是逐行解释执行,充分发挥 StarRocks 向量化执行引擎(SIMD 友好、缓存友好)的性能优势。
  2. DECIMAL 特化分支:当输入是 DECIMAL 系列类型(lt_is_decimal<Type>为真)时,会额外传入返回类型的precision(精度)与scale(小数位),确保定点小数取负后保持原有的精度与 scale 元信息;非 DECIMAL 类型(BIGINT、DOUBLE)则走无精度参数的简化路径。

真正的取负运算

取负的数学运算本身定义在 math_functions.h 中,实现极其简洁:

// negative DEFINE_UNARY_FN_WITH_IMPL(negativeImpl, v) { return -v; }

即对每一个元素直接执行一元取负运算-v。这也印证了negative()在语义上就是"逐元素的相反数",没有任何近似或舍入逻辑——这正是它能对 DECIMAL 类型保持精确的原因。

positive()的对称设计

在 math_functions.h 中,positive()的实现是直接返回输入列(std::move(*columns[0]).mutate(),即原样透传),而negative()则真正执行取负。两者共同构成 StarRocks 对一元正负号运算的函数化封装,便于优化器统一识别与推导。

前端 FE 中的注册、类型推导与统计信息

函数注册

negative是 StarRocks 内置函数,在 FE 侧通过常量 FunctionSet.NEGATIVE 登记函数名,并作为一元数学函数注册进内置函数表,供 SQL 解析与绑定阶段按名称解析。

DECIMAL 类型保持

在 DecimalV3FunctionAnalyzer.java 中,NEGATIVE被归入DECIMAL_UNARY_FUNCTION_SET

public static final Set<String> DECIMAL_UNARY_FUNCTION_SET = new ImmutableSortedSet.Builder<>(String::compareTo) .add(FunctionSet.ABS).add(FunctionSet.POSITIVE).add(FunctionSet.NEGATIVE) .add(FunctionSet.MONEY_FORMAT).add(FunctionSet.MATERIALIZE).build();

这组函数被 FE 识别为"一元且不改变类型"的 DECIMAL 函数,在类型分析阶段保证negative(decimal_col)的结果类型仍为 DECIMAL(且精度、scale 与原列一致),与 BE 端传入precision/scale的特化实现前后呼应。这也是文档中"返回与输入相同数据类型"这一规则在类型系统层面的落地保证。

统计信息区间反转

在优化器的统计估算模块 ExpressionStatisticCalculator.java 中,NEGATIVE表达式的取值区间按如下规则推导:

case FunctionSet.NEGATIVE: double negativeMinValue = -minValue; double negativeMaxValue = -maxValue; minValue = Math.min(negativeMinValue, negativeMaxValue); maxValue = Math.max(negativeMinValue, negativeMaxValue); break;

即:对输入列的 [min, max] 区间取负后重新排序作为输出区间。由于取负会反转大小关系(-max变成最小值、-min变成最大值),代码用Math.min/Math.max重新规整边界。这一区间推导让优化器能够对negative(col)参与过滤或 JOIN 的场景做出更准确的行数估算,从而选择更优的执行计划。

与优化器的联动:单调递减与 Runtime Filter

negative()在优化器中还被识别为单调递减函数。在 ExpressionStatisticCalculator.java 附近的注释中明确写有:

  • NEGATIVE(x): exact -x, fixed-point only(对定点数精确取负);
  • NEGATIVE(x): y = -x (monotonic decreasing) => [l,u] -> [-u,-l], reverse order(单调递减,区间由 [l,u] 映射为 [-u,-l] 并反转顺序)。

单调性信息直接服务于Runtime Filter 表达式推导与 Join 谓词下推。仓库的 SQL 回归测试 test_runtime_filter_monotonic_expr 中就有对应的 JOIN 场景:

select p.id, b.id from rf_expr_probe_${uuid0} p join rf_expr_build_${uuid0} b on p.c_bigint * -1 = b.k_negative order by p.id, b.id;

该用例验证了c_bigint * -1(语义等价于negative(c_bigint)的负号形式)能够作为单调表达式参与 Runtime Filter 的构建与探测,从而在 JOIN 执行时通过过滤下推减少数据传输量、提升查询性能。

测试验证:DECIMAL 精确取负

negative()的正确性由 BE 单元测试覆盖。在 math_functions_test.cpp 的NegativeDecimalTest中:

  • 输入3333333333.2222222222,断言结果为-3333333333.2222222222
  • 输入740740740.716049,断言结果为-740740740.716049

该测试直接以DecimalColumn构造 DECIMALV2 列并调用MathFunctions::negative<TYPE_DECIMALV2>,验证了 BE 端向量化实现对高精度定点小数取负的逐位精确性(27 位精度下无任何精度损失),与文档中 DECIMALV2 的声明完全一致。

总结

negative()是一个看似简单、但设计严谨的一元数学函数:

  • 使用层面:接受BIGINTDOUBLE及 DECIMAL 家族六种数值类型,返回类型与输入完全一致,适用于金额冲销、坐标取反、区间镜像等业务场景;
  • 实现层面:BE 通过 math_functions.h 的negativeImpl(即return -v)配合严格一元向量化模板批量执行,DECIMAL 类型携带 precision/scale 确保精确取负;
  • 优化层面:FE 在 DecimalV3FunctionAnalyzer.java 中保证类型不变,并在 ExpressionStatisticCalculator.java 中做区间反转统计与单调递减推导,进而支撑 Runtime Filter 等查询优化。

掌握这些细节后,你可以在 StarRocks 中放心地将negative()用于任意数值列,并理解它在执行计划中的优化路径。如需查看更多数学函数,可参考 数学函数文档目录 及同目录下的其他函数说明。

【免费下载链接】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),仅供参考

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

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

立即咨询