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

一 、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 服务器时间精确。

猜你喜欢

转载自blog.csdn.net/keep_learn/article/details/115164110