DaZuiZui commented on issue #18428:
URL: https://github.com/apache/iotdb/issues/18428#issuecomment-5235641552

   ## 建议的功能定义与实现方向(中文)
   
   查看最新 master 后,我认为日历时长必须作为 CQ 的一等元数据,贯穿解析、RPC、持久化、恢复和调度全链路。只修改 
parseResampleClause,或者只在创建 CQ 时按当时日期换算一个月,后续调度仍然会漂移。
   
   ### 1. 用户可见语法与支持范围
   
   CQ 现有语法保持不变:
   
       CREATE [CONTINUOUS QUERY | CQ] <cq_id>
       [RESAMPLE
         [EVERY <duration>]
         [BOUNDARY <time_value>]
         [RANGE <start_offset> [, <end_offset>]]
       ]
       [TIMEOUT POLICY {BLOCKED | DISCARD}]
       BEGIN
         <select_into_statement>
       END
   
   建议支持的 duration 单位:
   
   - 日历单位:y/year、mo/month
   - 现有固定单位:w、d、h、m、s、ms、us、ns
   - 继续支持组合 duration,例如 1y2mo3d
   - 1y 归一化为 12 个自然月
   - d 和 w 仍分别表示固定 24 小时和 7 天;只有 mo/y 使用日历语义
   - 本功能不改变 CQ 查询正文支持的数据类型、聚合函数或 SELECT INTO 规则
   
   逻辑上,一个 duration 由“整数月部分”和“当前时间精度下的固定 tick 部分”组成。
   
   如果省略 EVERY,应完整继承 GROUP BY TIME 的 duration。因此 GROUP BY(1mo) 必须得到日历月 EVERY,而不是 
30 天。如果省略 RANGE,默认值仍是 startOffset = EVERY、endOffset = 0。
   
   ### 2. 日历调度语义
   
   所有日历运算都必须使用创建 CQ 时捕获并持久化的 session 时区。
   
   设 B 为 boundary,E 为 EVERY,Z 为 CQ 时区,n 为 occurrence 序号:
   
       executionTime(n) = calendarApply(B, n * E, Z)
   
   每个 occurrence 必须从原始 BOUNDARY 直接计算,不能在上一次 executionTime 上连续 
plusMonths(1),否则会产生漂移:
   
       错误:Jan-31 -> Feb-29 -> Mar-29
       正确:Jan-31 -> Feb-29 -> Mar-31
   
   月末采用“钳制到目标月份最后一个有效日期”的规则:
   
       2023-01-31 + 1mo = 2023-02-28
       2024-01-31 + 1mo = 2024-02-29
       2020-02-29 + 1y  = 2021-02-28
       2020-02-29 + 4y  = 2024-02-29
   
   为了保持现有文档中的 BOUNDARY 公式,并避免月末加减法不可逆,建议先在 duration 向量上完成 RANGE 加减:
   
       startTime(n) = calendarApply(B, n * E - startOffset, Z)
       endTime(n)   = calendarApply(B, n * E - endOffset, Z)
   
   这样即使 BOUNDARY 是 Jan-31 或 Feb-29,EVERY 1mo RANGE 1mo 也会产生连续窗口。
   
   TIMEOUT POLICY 的语义:
   
   - BLOCKED:即使已经延迟,也按 occurrence 顺序逐个执行;查询窗口基于计划执行时间,而不是实际开始执行的墙钟时间。
   - DISCARD:跳过已错过的 occurrence,直接跳到第一个不早于当前时间的合法 occurrence。
   - 查找 calendar occurrence 应使用估算加修正或二分,不能从 1970 年开始逐月循环。
   
   ### 3. 校验与兼容性
   
   保留现有正值约束:EVERY > 0、startOffset > 0、endOffset >= 0、startOffset > 
endOffset,以及当前的 startOffset >= EVERY 约束。
   
   日历时长和固定时长不存在永久全序:1mo 可能短于或长于 30d。因此校验时不能再把月份压成 30 天。对于含义随日期变化的混合比较,可以采用保守的 
min/max 判断;无法确定时应返回明确的语义错误。
   
   兼容性建议:
   
   - 在 TCreateCQReq 中追加 optional 的结构化 duration 字段,保留现有 i64 字段供旧版本读取
   - 新 ConfigNode 优先使用结构化值;旧请求按纯 fixed duration 解释
   - 为 CQInfo snapshot 增加格式版本,旧 snapshot 中的 duration 继续按固定时长读取
   - 不通过重新解析保存的 SQL 静默迁移已经持久化的 1mo/1y CQ;用户可以重新创建 CQ 以启用新语义
   - 只有全部 ConfigNode 完成升级后,才允许创建 calendar CQ
   
   DataNode 执行 RPC 仍然只需要接收最终的 startTime/endTime,主查询执行引擎无需感知 calendar 
duration。查询 timeout 应使用本次 occurrence 到下一次 occurrence 的实际距离,不能继续使用 30 天近似值。
   
   ### 4. 实现前需要确认的两个语义
   
   1. calendar EVERY 省略 BOUNDARY 时,是否应该自动对齐 CQ 时区的本地自然月界?我的建议是使用该 CQ 时区中的 
1970-01-01 00:00:00 作为默认日历锚点;显式 BOUNDARY 0 仍表示 Unix epoch 
instant。因此需要记录用户是否显式指定了 BOUNDARY。
   2. RANGE 是否采用上述“锚定 duration 向量”公式?它既保持现有文档公式,也能保证 EVERY == RANGE 
时月末窗口连续;直接从已经钳制的 executionTime 反向减月做不到这一点。
   
   建议测试覆盖:显式及从 GROUP BY 继承的 1mo/1y、Jan-31、闰日、DST 时区、ms/us/ns 精度、BLOCKED/DISCARD 
追赶、leader 恢复、procedure/plan 序列化和旧 CQ snapshot。
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to