【问题标题】:MySQL inconsistent date orderingMySQL 不一致的日期排序
【发布时间】: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 应该可以正确排序它们...

标签: mysql hibernate grails


【解决方案1】:

您可以将 id 字段添加为等分母,因为插入是原子(先到先得)

 ... 40) ORDER BY u.last_updated ASC, id ASC;

分别

 ... 40) ORDER BY u.last_updated DESC, id DESC;

SQL fiddle here

【讨论】:

    【解决方案2】:

    尝试将last_updated 字段更改为DATETIME(6) 而不是DATETIME。这样你就可以获得微秒级的分辨率。 MySQL Reference.

    【讨论】:

    • 谢谢 - 我认为你是对的。我试试看
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-20
    • 1970-01-01
    • 2023-03-13
    • 2016-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多