【发布时间】:2015-10-05 01:15:45
【问题描述】:
我在调试失败的集成测试时遇到了一个奇怪的问题。根据以下查询的排序方向(ASC/DESC),我似乎得到不一致的结果:
SELECT u.id, u.last_updated FROM user u WHERE u.id IN (36, 37, 38, 39, 40) ORDER BY u.last_updated ASC;
上面的查询返回这些结果,正如我所期望的那样:
id last_updated
=======================
36 2015-07-15 19:45:34
37 2015-07-15 19:45:34
38 2015-07-15 19:45:34
39 2015-07-15 19:45:35
40 2015-07-15 19:45:35
但是,如果我将排序顺序从 ASC 切换到 DESC,我会得到:
id last_updated
=======================
39 2015-07-15 19:45:35
40 2015-07-15 19:45:35
36 2015-07-15 19:45:34
37 2015-07-15 19:45:34
38 2015-07-15 19:45:34
当查询是降序时,就好像MySQL无法以超过秒的精度区分日期之间的差异。
如果我更改日期以使每个 last_updated 值之间有 1 秒的间隔,则排序在两个方向上都可以正常工作。
这些查询是通过基于 Grails / Hibernate 的应用程序执行的。如果我在我的应用程序中添加一些调试代码,我可以看到日期都不同并且精确到 1 毫秒:
1436989535410, 1436989535646, 1436989534516, 1436989534990, 1436989534751
所以数据被存储到足够的精度......
用户表声明如下:
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`last_updated` datetime NOT NULL,
...
)
我使用的是 MySQL 5.6.15。
在使用 H2 Java 内存数据库进行测试时,相同的查询/集成测试可以正常工作。
编辑:
有趣的是,看起来确实丢失了一些精度。如果我运行以下查询:
SELECT u.id, u.last_updated, UNIX_TIMESTAMP(u.last_updated) FROM user u WHERE u.id IN (36, 37, 38, 39, 40) ORDER BY u.last_updated ASC;
我明白了:
id last_updated unix timestamp
=======================================
36 2015-07-15 19:45:34 1436985934
37 2015-07-15 19:45:34 1436985934
38 2015-07-15 19:45:34 1436985934
39 2015-07-15 19:45:35 1436985935
40 2015-07-15 19:45:35 1436985935
我猜 Hibernate 正在缓存更精确的持久化前日期值,并在我尝试在我的应用程序中调试时将它们返回给我...
【问题讨论】:
-
时间戳是自 1970 年以来的秒数,它不包含毫秒
-
补充@Mihai 备注:所以你升序排序中的升序ID只是巧合。
-
道歉 - 时间戳是错误的词。日期保存为 MySQL
datetimes -
一个 DATETIME 或 TIMESTAMP 值可以包括一个尾随小数秒部分,精度高达微秒(6 位)。尽管可以识别这个小数部分,但它会从存储的值中丢弃dev.mysql.com/doc/refman/5.5/en/datetime.html
-
在我的应用程序层中,我可以看到这些值已保持(至少)毫秒精度。 MySQL 应该可以正确排序它们...