You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GridDB Java API查询毫秒级时间戳数据时丢失行问题

GridDB 5.3时间序列容器毫秒级时间戳查询丢失数据问题

测试环境:GridDB Community Edition 5.3,通过Docker Desktop在macOS 14.4(Apple M1)上运行Linux容器。

问题现象:向时间序列容器插入带毫秒级时间戳的数据行后,执行范围查询时,明明在时间范围内的一行数据被跳过。

可复现Java代码

import java.sql.Timestamp;
import java.util.*;

public class MillisGapDemo {
    public static void main(String[] args) throws Exception {
        Properties p = new Properties();
        p.setProperty("clusterName", "defaultCluster");
        p.setProperty("notificationAddress", "239.0.0.1");
        p.setProperty("notificationPort", "31999");
        p.setProperty("user", "admin");
        p.setProperty("password", "admin");
        GridStore gs = GridStoreFactory.getInstance().getGridStore(p);

        ContainerInfo info = new ContainerInfo();
        info.setType(ContainerType.TIME_SERIES);
        info.setRowKeyAssigned(true);
        info.setColumnInfoList(List.of(
            new ColumnInfo("ts", GSType.TIMESTAMP),
            new ColumnInfo("value", GSType.DOUBLE)
        ));
        TimeSeries<Row> ts = gs.putTimeSeries("millis_test", info, true);

        ts.put(Arrays.asList(
            createRow(ts, Timestamp.valueOf("2023-01-01 10:00:00.500"), 25.0),
            createRow(ts, Timestamp.valueOf("2023-01-01 10:00:01.000"), 26.0)
        ));

        RowSet<Row> rs = ts.query(
            "SELECT * WHERE ts >= TIMESTAMP('2023-01-01 10:00:00') AND ts < TIMESTAMP('2023-01-01 10:00:02')"
        ).fetch();

        System.out.println("Rows returned: " + rs.size());
    }

    private static Row createRow(TimeSeries<Row> ts, Timestamp t, double v) {
        Row r = ts.createRow();
        r.setTimestamp(0, t);
        r.setDouble(1, v);
        return r;
    }
}

结果对比

  • 预期结果:返回两行数据(10:00:00.500和10:00:01.000)
  • 实际结果:仅返回10:00:01.000的行,10:00:00.500的行被跳过

已尝试的操作

  • 使用不同比较运算符(>=、<、>、<=)——问题依旧
  • 切换java.sql.Timestamp和java.util.Date类型
  • 在查询中使用TIMESTAMPADD(MICROSECOND, …)——仍跳过第一行
  • 在客户端显式设置时区(timeZone = "+00:00")

疑问与解答

1. GridDB内部会对时间戳进行四舍五入或截断到微秒吗?

GridDB的TIMESTAMP类型原生支持微秒级存储,不会主动对时间戳进行四舍五入,但存储时会保留传入的全部精度。问题出在字符串形式的时间戳解析:当使用TIMESTAMP('2023-01-01 10:00:00')这种仅到秒级的字符串时,内部会将其解析为该秒的0微秒,而插入的10:00:00.500实际是10:00:00.500000微秒,若客户端与服务器的精度转换逻辑存在偏差,可能导致毫秒级时间戳被误判为小于秒级起始时间。

2. 查询毫秒精度时间范围的最佳实践

  • 优先使用参数化查询:直接传递java.sql.Timestamp对象,避免字符串解析带来的精度损失,示例调整:
    Timestamp start = Timestamp.valueOf("2023-01-01 10:00:00.000");
    Timestamp end = Timestamp.valueOf("2023-01-01 10:00:02.000");
    RowSet<Row> rs = ts.query("SELECT * WHERE ts >= ? AND ts < ?", start, end).fetch();
    
  • 明确指定微秒精度:若必须使用字符串查询,需补充微秒部分,比如TIMESTAMP('2023-01-01 10:00:00.000000')。

3. 这是否是客户端与服务器时区不匹配导致的?

有可能。即使客户端设置了时区,若GridDB服务器时区不一致,时间戳会被转换为服务器时区存储,查询时再转回客户端时区,可能引发毫秒级偏差。可以通过以下方式验证:

  • 在GridDB控制台执行SHOW CLUSTER PROPERTIES查看时区配置;
  • 插入数据时打印Timestamp的getTime()数值,查询时对比服务器端存储的时间戳数值。

4. 如何可靠返回亚秒级时间范围内的所有行?

  • 使用参数化查询传递Timestamp对象:这是最可靠的方式,直接传递带完整精度的时间戳,避免解析误差;
  • 调整查询边界:若必须用字符串查询,可将起始时间设为目标时间的前1微秒,比如TIMESTAMP('2023-01-01 09:59:59.999999'),确保覆盖所有亚秒级数据;
  • 验证存储精度:插入数据后执行SELECT ts FROM millis_test,确认存储的时间戳精度与插入值一致。

内容的提问来源于stack exchange,提问作者Panuganti Jayanth Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 21:05:10