Mysql8.0 数据按照时间排序不稳定引发的思考

本文探讨了MySQL内部和外部排序的原理,指出快速排序的不稳定性可能导致排序顺序变化。当根据时间排序时,更新可能导致顺序变动,解决方案包括增加排序字段和提高时间精度。在MySQL8.0中,可通过设置datetime字段的微秒精度解决。同时,文章还介绍了Java中获取微秒时间的方法,并强调了确保服务器时间精确的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 、mysql order by 原理

内部排序

指的是待排序记录存放在计算机随机存储器中进行的排序过程,也就是排序全部在服务器内存中进行。

思考:mysql 的排序过程全部是在内存中进行的吗。

外部排序

指的是待排序记录的数量很大,以致内存一次不能容纳全部记录,在排序过程中尚需对外存进行访问的排序过程。

不稳定排序

对于mysql 来说

排序这个动作,可能在内存中完成,也可能需要使用外部排序,这取决于排序所需的内存和参数

sort_buffer_size。sort_buffer_size,就是 MySQL 为排序开辟的内存(sort_buffer)的大小。如果要排序的数据量小于 sort_buffer_size,排序就在内存中完成。但如果排序数据量太大,内存放不下,则不得不利用磁盘临时文件辅助排序。

在这里插入图片描述
mysql sort_buffer 排序使用了快速排序,快速排序是一种不稳定排序, 在时间相同的时候,不能保证每次排序数据位置相同。

二、根据时间排序发生的问题

数据更新前
在这里插入图片描述数据更新之后 id 623 排到末尾
在这里插入图片描述
虽然根据时间排序规则,返回的结果没有逻辑问题,但对于用户来说就是消息列表更新之后, 消息顺序发生变动。
这里需要进一步深入mysql 源码理解 整个排序过程的细节,为什么更新操作之后,排序顺序会变

分析完问题 接下来 看看解决问题的几种思路

增加排序字段

根据时间和id 排序,这样的排序会保证了结果的稳定性,但是对于mysql来说, 排序是一个比较耗费资源的操作,本来一个排序字段可以完成的操作尽量不要增加排序字段。

精确publishTime

mysql8.0 中 的datetime 字段默认小数后0位, 那么智能精确到秒,增加小数点后位数 6 精确到微秒。

批量写入数据表的时候 使用 now(6) 来生成微秒的时间数据。

如果是java 中entity 中赋值时间字段,则需要获取微秒时间。

MYSQL 获取微秒时间

now() 只能返回精确到秒的时间

获取精确到毫秒可以使用now(3)
精确到微秒 now(6)

mysql8.0 仅支持微秒

SELECT
	NOW( ) AS A,
	NOW( 3 ) AS b,
	NOW( 6 ) AS c;

在这里插入图片描述

java 中获取微秒时间

获取系统时间毫秒:

 public Date() {
        this(System.currentTimeMillis());
    }

一般系统时间精确到毫秒可以有效区分,但是遇到高并发系统,就需要进一步精确到微秒了
1毫秒=1000微秒=1000纳秒

获取微秒:

Date.from(Instant.now().truncatedTo(ChronoUnit.MICROS))

改变ChronoUnit.MICROS 可以选择返回的时间精度

java.time中的类解析为nanoseconds,比旧的日期时间类和Joda-Time使用的milliseconds更精细。

时钟实施

在jdk11 中

Instant

对象可以提供精确到纳秒的时间,而且是线程安全的。

可以通过

  System.out.println(ZonedDateTime.now(ZoneId.of("America/Montreal")));
  System.out.println(Clock.system(ZoneId.of("Asia/Shanghai")).instant());
  System.out.println(Date.from(Clock.system(ZoneId.of("Asia/Shanghai")).instant()));

获取精确时间。

mysql和java 获取的时间都是基于所在服务器时间,如果遇到时间不一致问题,先确保unix 服务器时间精确。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值