Java LocalDateTime 到 byte[] 的高效转换

问题描述 投票:0回答:1

我需要读取一个包含 300 多百万个

TIMESTAMP
的数据库表(已排序的行),就像 Java 中的
LocalDateTime
一样,并且我需要获取所有这些表的单个哈希值。然后,我需要从迁移的数据库(不同品牌和所有)中获取相同的哈希值并获取哈希值进行比较。

我想我可以使用

LocalDateTime.toString()
来获取一个字符串,然后获取它们的字节并使用它们来更新哈希值。

但是,它是 3 亿个值……两倍。我将在数据库迁移期间运行它,所以希望它应该很快。

获取 LocalDateTime 的字节表示的有效方法是什么?

java hash byte java-time
1个回答
0
投票

很大程度上取决于您的数据库引擎。当询问“我需要使用数据库引擎每天两次操作 X 几百万次”时,通常就是这种情况。 SQL 是语法标准,而不是性能配置文件。

对于这个答案的其余部分,我将假设使用 postgreSQL。

PostgreSQL 在这方面遵循 SQL 标准,并将类型

timestamp
视为
timestamp without time zone
的缩写,这确实与 java 类
java.time.LocalDateTime
匹配得最好。

但是,即使您只是在 JDBC 结果集上调用

rs.getObject(1, java.time.LocalDateTime.class)
,也必须发生大量转换。是的,JDBC 4.2 规范将保证这一点有效,并且,是的,这会导致有保证的无损转换。然而,Java 的 LDT 类型具有大量字段(一个代表年份,一个代表月份,等等),而 psql 将数据位打包为 8 字节序列。因此,如果您要求 JDBC 为您提供一个
LocalDateTime
对象,那么您就已经几乎输掉了比赛——这就是在做大量不需要的工作。事实上,如果目标是产生哈希值,那是非常痛苦的。

所以,如果可以的话,不要这样做。让数据库开始工作:

SELECT EXTRACT(epoch FROM TIMESTAMP '1999-01-08 04:05:06')

然后您可以通过 JDBC

rs.getLong(1)
获取该信息。

这将为您提供 915768306。对于 UTC 时区,这是自纪元(1970 年 1 月 1 日午夜)以来经过的秒数。如果您发现毫秒值相关,则必须选择

1000 * EXTRACT

try (var stmt = con.createStatement()) {
  try (var rs = stmt.executeQuery("SELECT 1000 * EXTRACT(epoch FROM TIMESTAMP '1999-01-08 04:05:06')")) {
    rs.next();
    long a = rs.getLong(1);
    long b = LocalDateTime.of(1999, 1, 8, 4, 5, 6).toInstant(ZoneOffset.UTC).toEpochMilli();
    assertEquals(a, b); // this will hold.
  }
}

这样更快吗?大概。当然,将 LDT 转换为字符串并进行散列处理会使情况变得更糟。 如果必须的话,只需在 LDT 上调用 .hashCode() 即可。

© www.soinside.com 2019 - 2024. All rights reserved.