ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

StarRocks 日期函数 date_sub / subdate 完全指南:语法、参数、返回值与底层实现解析

StarRocks 日期函数 date_sub / subdate 完全指南:语法、参数、返回值与底层实现解析 StarRocks 日期函数 date_sub / subdate 完全指南语法、参数、返回值与底层实现解析【免费下载链接】starrocksThe worlds 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/starrocksdate_sub别名subdate是 StarRocks 中用于从日期时间值中减去指定时间间隔的核心函数广泛应用于时间窗口过滤、滚动区间统计、增量数据回溯等场景。本文以官方文档 date_sub.md 为骨架结合 StarRocks FE前端与 BE后端源码系统讲解其语法、参数单位、边界行为、完整示例以及从 SQL 解析、常量折叠到向量化执行的底层实现链路帮助你准确、高效地使用这一日期时间函数族。函数概述date_sub 与 subdate 的关系date_sub与subdate是完全等价的两个函数名语义完全相同——都是从给定的日期或日期时间中减去指定长度的时间间隔。在 StarRocks 的函数注册表中两者被同时注册FunctionSet.java 中分别定义了DATE_SUB date_sub与SUBDATE subdate两个函数名常量ScalarOperatorFunctions.java 通过ConstantFunction注解为subdate和date_sub注册了相同的函数签名(DATETIME, INT) - DATETIME且标记为isMonotonic true单调函数详见下文谓词化简一节。因此在实际 SQL 中你可以根据团队编码习惯任选其一两者在功能、性能与返回值上没有任何差异。语法与参数详解函数签名DATETIME DATE_SUB(DATETIME|DATE date, INTERVAL expr type)参数说明参数类型要求含义dateDATE 或 DATETIME合法的日期/日期时间表达式是减法运算的基准时间exprINT要减去的时间间隔数值可为负数负数等价于加上该间隔type时间单位关键字时间间隔的单位决定expr的语义type支持的时间单位单位关键字说明引入版本YEAR年全版本QUARTER季度全版本MONTH月全版本DAY天全版本HOUR小时全版本MINUTE分钟全版本SECOND秒全版本MILLISECOND毫秒3.1.7 及以后MICROSECOND微秒3.1.7 及以后版本注意MILLISECOND与MICROSECOND两个单位自 StarRocks 3.1.7 起才可用低于该版本会报语法错误。这与 BE 侧time_functions.cpp中按单位宏展开的millis_add/millis_sub、micros_add/micros_sub函数族一一对应见下文BE 端实现。语法细节函数名大小写不敏感date_sub与DATE_SUB均合法单位关键字同样不区分大小写INTERVAL 2 DAY与INTERVAL 2 day等价示例中两种写法均有出现date既可以是字符串字面量如2010-11-30 23:59:59也可以是DATE/DATETIME类型的列、表达式或函数返回值。返回值与边界行为date_sub始终返回DATETIME 类型的值返回值保留原时间的小时、分钟、秒及小数部分。需要特别注意以下边界行为无效日期返回 NULL如果输入的日期本身不存在例如2020-02-302 月没有 30 号函数直接返回NULL而不是执行进位修正。类型不合法返回 NULL若date不是合法的 DATE 或 DATETIME 值同样返回NULL。DATE 类型输入自动按 DATETIME 处理当输入为纯日期如2010-11-30时函数会将其视为2010-11-30 00:00:00参与运算结果仍以 DATETIME 返回。这在下面的示例中可以看到减去 2 小时后得到2010-11-29 22:00:00体现了借位到前一天的日期回退逻辑。跨月/跨年借位按 DAY 等短单位做减法时会自动进行借月、借年运算正确处理闰年与大小月。月份相关的月末溢出语义按 MONTH/QUARTER/YEAR 做减法时StarRocks 遵循直接减月份字段超出月末则返回该月最后一天的常见日期库语义即2010-03-31减 1 个月得到2010-02-28。完整示例以下是官方文档 date_sub.md 给出的全部示例逐一展开说明-- 示例 1减去 2 天时间部分保持不变 select date_sub(2010-11-30 23:59:59, INTERVAL 2 DAY); ------------------------------------------------- | date_sub(2010-11-30 23:59:59, INTERVAL 2 DAY) | ------------------------------------------------- | 2010-11-28 23:59:59 | ------------------------------------------------- -- 示例 2DATE 类型输入按 00:00:00 处理减去 2 小时发生跨天借位 select date_sub(2010-11-30, INTERVAL 2 hour); ----------------------------------------- | date_sub(2010-11-30, INTERVAL 2 HOUR) | ----------------------------------------- | 2010-11-29 22:00:00 | ----------------------------------------- -- 示例 3无效日期2020 年 2 月没有 30 号返回 NULL select date_sub(2010-02-30, INTERVAL 2 DAY); ---------------------------------------- | date_sub(2010-02-30, INTERVAL 2 DAY) | ---------------------------------------- | NULL | ---------------------------------------- -- 示例 4减去 2 个季度共 6 个月 select date_sub(2010-11-30 23:59:59, INTERVAL 2 QUARTER); ----------------------------------------------------- | date_sub(2010-11-30 23:59:59, INTERVAL 2 QUARTER) | ----------------------------------------------------- | 2010-05-30 23:59:59 | ----------------------------------------------------- -- 示例 5使用别名 subdate 减去 2 毫秒3.1.7 及以后 select subdate(2010-11-30 23:59:59, INTERVAL 2 millisecond); -------------------------------------------------------- | subdate(2010-11-30 23:59:59, INTERVAL 2 MILLISECOND) | -------------------------------------------------------- | 2010-11-30 23:59:58.998000 | -------------------------------------------------------- -- 示例 6减去 2 微秒返回微秒精度3.1.7 及以后 select date_sub(2010-11-30 23:59:59, INTERVAL 2 microsecond); --------------------------------------------------------- | date_sub(2010-11-30 23:59:59, INTERVAL 2 MICROSECOND) | --------------------------------------------------------- | 2010-11-30 23:59:58.999998 | ---------------------------------------------------------补充示例负的 exprexpr支持 INT 类型负数INTERVAL -2 DAY等价于加 2 天。这一特性可用于在一条 SQL 中同时表达回退与前推语义select date_sub(2010-11-30 23:59:59, INTERVAL -2 DAY); -- 结果2010-12-02 23:59:59与其他日期时间函数的对照为便于选型这里给出与date_sub同族或易混淆函数的对照相关文档见 日期时间函数索引函数语义典型场景date_sub/subdate减去指定时间间隔单位覆盖年/季/月/日/时/分/秒/毫秒/微秒通用时间回退计算date_add/adddate加上指定时间间隔与date_sub互为逆运算过期时间、未来时间计算文档见 date_add.mddays_sub/days_add仅支持按天为单位的加减性能敏感且只需按天计算的场景文档见 days_sub.mdtimestampadd标准 SQL 风格timestampadd(unit, interval, datetime)需要符合 ANSI SQL 语法的场景文档见 timestampadd.mdyears_sub/months_sub等单单位专用函数如 years_sub.md、months_sub.md只针对单一时间单位、且希望函数签名更明确的场景从实现上看这一整族按单位加减的函数在 BE 端由同一套宏模板统一生成见下节源码分析。源码实现原理FE 端解析、重写与常量折叠date_sub家族date_add、adddate、date_sub、subdate、days_sub在 StarRocks FE 的 SQL 解析阶段即被特殊处理。AstBuilder.java 中定义了DATE_FUNCTIONS列表注释明确指出这类日期函数在解析时会被重写为TimestampArithmeticExpr一种专门的时间戳算术表达式节点而非普通函数调用。这意味着语法上date_sub(date, INTERVAL expr type)与date - INTERVAL expr type的算术写法被统一为同一类表达式后续优化器可对这类表达式进行专门的下推、化简与常量折叠。常量折叠当date与expr均为常量时FE 会在优化阶段直接算出结果。这在 ScalarOperatorFunctions.java 中通过ConstantFunction(name date_sub, argTypes {DATETIME, INT}, returnType DATETIME, isMonotonic true)注册——isMonotonic true表明该函数关于时间参数是单调的。谓词化简monotonic 的应用正因为date_sub被标记为单调函数SimplifiedPredicateRule.java 将其纳入TIME_FNS与TIME_FN_NAMES映射表用于谓词等价变换。例如源码注释中给出的化简规则L442-- 优化器将嵌套的时间函数化简减少一次计算 date_sub(date_add(x, 1), 2) - date_sub(x, 1)这意味着在写 SQL 时即使表达式被写成了嵌套形式优化器也会自动合并化简不会产生多余的计算开销。BE 端向量化执行与模板化实现BE后端侧的实现位于 time_functions.cpp约 L944-L999其核心是模板宏驱动的函数族生成template TimeUnit UNIT TimestampValue timestamp_add(TimestampValue tsv, int count) { return tsv.addUNIT(count); } #define DEFINE_TIME_ADD_FN(FN, UNIT) ... { return timestamp_addUNIT(timestamp, value); } #define DEFINE_TIME_SUB_FN(FN, UNIT) ... { return timestamp_addUNIT(timestamp, -value); }关键设计点减法是加法的负数形式DEFINE_TIME_SUB_FN直接复用timestamp_addUNIT将value取负后调用即减 N 个单位 加 -N 个单位。这与文档中expr支持负 INT 的行为完全一致。一个模板覆盖全部单位通过DEFINE_TIME_ADD_AND_SUB_FN(years, TimeUnit::YEAR)等宏调用一次生成years_add/years_sub、quarters_add/quarters_sub、months_add/months_sub、weeks_add/weeks_sub、days_add/days_sub、hours_add/hours_sub、minutes_add/minutes_sub、seconds_add/seconds_sub、millis_add/millis_sub、micros_add/micros_sub共 20 个函数覆盖了date_sub支持的全部type单位含 3.1.7 起新增的毫秒、微秒。向量化执行所有函数均返回ColumnPtr通过DEFINE_TIME_CALC_FN定义(TYPE_DATETIME, TYPE_INT) - TYPE_DATETIME的二元向量化签名BE 会以批处理方式同时对整列数据求值这正是 StarRocks 面向 OLAP 大规模列式计算性能的基础。单元测试保障time_functions_test.cpp 中包含了yearAddTest、quarterAddTest、millisAddTest、yearOverflowTest等测试用例覆盖年/季度/毫秒加减及溢出场景验证了各单位的计算正确性。从 SQL 到结果的全链路一条SELECT date_sub(2010-11-30 23:59:59, INTERVAL 2 DAY)的完整执行路径为FE 解析AstBuilder识别date_sub属于DATE_FUNCTIONS家族构建TimestampArithmeticExpr节点见 AstBuilder.javaFE 优化若参数全为常量触发常量折叠直接产出结果若出现在谓词中利用单调性进行等价化简见 SimplifiedPredicateRule.javaBE 执行生成计划下发到 BE调用time_functions.cpp中按TimeUnit模板实例化的days_sub等向量化函数对整列批量求值见 time_functions.cpp返回结果以 DATETIME 列形式返回给客户端。典型使用场景1. 时间窗口过滤滚动近 N 天数据-- 查询最近 7 天产生的订单 SELECT order_id, order_time, amount FROM orders WHERE order_time date_sub(now(), INTERVAL 7 DAY);2. 环比/同比区间统计-- 本周销售额与上周销售额对比 SELECT SUM(IF(ts date_sub(now(), INTERVAL 7 DAY), amount, 0)) AS this_week, SUM(IF(ts date_sub(now(), INTERVAL 14 DAY) AND ts date_sub(now(), INTERVAL 7 DAY), amount, 0)) AS last_week FROM sales;3. 与聚合函数配合生成时间分桶-- 按过去 30 天内每 7 天为一桶聚合 SELECT date_sub(event_day, INTERVAL MOD(DATEDIFF(now(), event_day), 7) DAY) AS bucket_start, COUNT(*) FROM user_events WHERE event_day date_sub(now(), INTERVAL 30 DAY) GROUP BY bucket_start;4. 物化视图 / 增量计算中的时间推进date_sub也常与date_add成对出现在物化视图定义或 ETL 任务的时间游标计算中例如MVMaintenance相关的时间推进逻辑中通过date_sub(last_refresh_time, INTERVAL 1 DAY)回溯增量窗口起点。注意事项与最佳实践优先使用 DAY 等字段无关单位对于只需要按天计算的场景days_sub在语义上与date_sub(..., INTERVAL n DAY)等价且函数签名更聚焦可读性更好。注意月末与季度边界当date落在月末如 3 月 31 日时按MONTH/QUARTER/YEAR减法会发生月末收敛结果为 2 月 28/29 日。若业务需要同一天号建议改用ADD_MONTHS语义或自行按DAY计算。无效日期不会自动修正传入2020-02-30之类不存在的日期会直接得到NULL在 ETL 场景中建议结合COALESCE或CASE WHEN处理避免 NULL 污染下游统计。毫秒/微秒单位依赖版本使用MILLISECOND、MICROSECOND前请确认集群版本 ≥ 3.1.7否则语句无法通过语法校验。负间隔是合法输入expr支持 INT 负数可等价实现加法但为可读性考虑正向推进建议直接使用date_add相关文档见 date_add.md。类型精度返回值为 DATETIME含微秒精度若业务只关心日期部分可再配合to_date或date_trunc收敛参见 to_date.md。延伸阅读官方英文文档date_sub.md、中文文档date_sub.md逆运算date_add.md、adddate.md单单位专用函数days_sub.md、years_sub.md、months_sub.md、quarters_sub.mdSQL 标准风格timestampadd.md、timestampdiff.md日期时间函数总览date-time-functions.mdx源码参考AstBuilder.java、ScalarOperatorFunctions.java、SimplifiedPredicateRule.java、time_functions.cpp、time_functions_test.cpp【免费下载链接】starrocksThe worlds 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),仅供参考
返回列表