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
相关产品推荐
相关产品推荐

