MySQL技巧之函数篇:雪花算法之MySQL编写实例一的升级版

引言:前阵子(大概23年吧),有JAVA开发的同事提出,要改掉现系统中MySQL库中各表的自增ID作为主键的现有方案,想改用bigint(20) 来存储java程序的雪花id值作为主键的方案。目的是解决多系统多数据库数据合并问题。
问题来了,没了自增ID,你怎么写一条以前很简单又普通的插入语句呢?这个主键要填雪花id值,雪花id是什么鬼?MySQL的内置函数里有这东西吗?没有!好吧,我只好随便填一个大概的id了!
如果我要插入N行记录呢?是不是更复杂呢,以后再讨论。
升级版从这里接着讨论。
阅读过我上一稿的朋友不知道想过没有?同时间插入N行结果会怎么样?
例如
SELECT fun_Twitter_SnowFlake(512) AS 雪花ID1, tt.*
FROM my_test_table tt
借用之前博文用过的表,显示一下同时产生N行记录,发现还是有重复的机会的!
在这里插入图片描述
多试几次就看到重复了!所以实例一只适合单个的雪花ID的产生,如果要想同一时间产生N多个的雪花ID,就要看升级版了。

先插入一张图,不至于乱了我的排版。
在这里插入图片描述

CREATE FUNCTION fun_Twitter_SnowFlake_seq(p_mic_id INT, p_seq INT) RETURNS BIGINT(20)
BEGIN
/*
获取 雪花ID 升级版
参数:p_mic_id 主机ID 注:0至1023之间,建议用0(二进制十个0)或者512(二进制1后九个0),假设用512
p_seq 指定开始序号 注:0至4095之间,通常为1。如果为0,按随机数取。
返回:bigint 类型值

算法参考的网站: https://blog.csdn.net/liudao51/article/details/103007892
感谢 Twitter 的雪花算法定义    
全部结构标识(1+41+10+12=64)加起来刚好64位,刚好凑成一个Long型。     
以2015-01-01 00:00:00的毫秒时间戳为起点 1420041600000,计算当前时间的时间戳差。    

传说中高人用 MySQL 函数实现。
调用实例1:SELECT fun_Twitter_SnowFlake_seq(512,0);  -- 假设主机ID=512, 序号将取随机数
调用实例2:SELECT fun_Twitter_SnowFlake_seq(512,1);  -- 假设主机ID=512, 开始序号为1
调用实例3:产生同1毫秒递增的雪花ID, 用于批量插入记录时指定主键。

SELECT @a AS 指定开始序号, fun_Twitter_SnowFlake_seq(512,@a:=@a+1), tt.*
FROM my_test_table tt
LEFT JOIN (SELECT @a:=0 FROM DUAL) a ON 1=0

注意:使用后起点时间戳不能再更改!!本例以2015-01-01 00:00:00的毫秒时间戳为起点

创建时间:2024-01-26
更新时间:2024-01-27 fun_Twitter_SnowFlake 版的升级版,用于批量插入语句中使用 
更新时间:2024-02-28 再升级版,解决一毫秒插入上百万行的问题

*/
DECLARE v_return_bigint BIGINT; # 返回值
DECLARE v_seq INT; # 临时变量,合并 主机ID 与 流水ID
SET v_return_bigint = 0;
SET p_seq = IFNULL(p_seq, 0); # 如果参数为 Null 当作 0处理
IF p_seq = 0 THEN
SET v_seq = ((p_mic_id MOD 1024) << 12) + (MOD(FLOOR(RAND()*10000), 4096));
SET v_return_bigint =
((FLOOR(UNIX_TIMESTAMP(CURRENT_TIMESTAMP(3))*1000) - FLOOR(UNIX_TIMESTAMP(‘2015-01-01 00:00:00’)*1000)) << 22) + v_seq;
ELSE
IF p_seq < 4096 THEN
SET v_seq = ((p_mic_id MOD 1024) << 12) + (p_seq MOD 4096);
SET v_return_bigint =
((FLOOR(UNIX_TIMESTAMP(CURRENT_TIMESTAMP(3))*1000) - FLOOR(UNIX_TIMESTAMP(‘2015-01-01 00:00:00’)*1000)) << 22) + v_seq;
ELSE
SET v_seq = (((p_mic_id >> 9) << 9) << 12) + (p_seq MOD 2097152);
SET v_return_bigint =
((FLOOR(UNIX_TIMESTAMP(CURRENT_TIMESTAMP(3))*1000) - FLOOR(UNIX_TIMESTAMP(‘2015-01-01 00:00:00’)*1000)) << 22) + v_seq;
END IF;
END IF;
RETURN v_return_bigint;
END

以上为去掉部分注解后的函数,提交后变左对齐了,乱了我的格式!更详细的编写细节思路,清晰的书写结构,请阅读图片中的原文。
OK,测试一下,只产生一个雪花ID,参阅函数的调用实例。
再测试大批量产生雪花ID,这里要用一个变量@a让它产生连续的雪花ID:
SELECT @a AS 指定开始序号, fun_Twitter_SnowFlake_seq(512,@a:=@a+1), tt.*
FROM my_test_table tt
LEFT JOIN (SELECT @a:=0 FROM DUAL) a ON 1=0
在这里插入图片描述
就算一毫秒变态的插入一百万行都没问题!

妙!高!实在是高!
加粉丝看
MySQL技巧系列之《未经证实的葵花宝典》:一篇可以当饭吃的MySQL文章,值得收藏

总结用MySQL语句编写一个雪花算法函数,方便获取雪花ID,解决同一时间插入N行记录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值