68人参与 • 2025-08-08 • MsSqlserver
在我的印象中用到这个雪花id比较少,可能是我接触的大型项目或者开源项目比较少,同时接触到中大型分布式也比较少,基本都是自研系统,用的是自增id和guidvalue作为唯一编号。
最近项目上使用了一套第三方框架代码,使用了雪花id作为表的唯一主键,并且之前表没有这个字段,需要进行表迁移的同时初始化雪花id字段值。
因此,趁这次机会简单总结下雪花id以及在sql server上如何生成雪花id。
雪花id是twitter开发的一种分布式唯一id生成算法,主要用于在分布式系统中生成全局唯一的id标识符。它的名称来源于"自然界中没有两片完全相同的雪花"这一概念,象征着每个生成的id都是独一无二的。
标准的雪花id由以下三部分组成(共64位):
| 1位符号位 | 41位时间戳 | 10位工作节点id | 12位序列号 |
具体分解:
假设一个雪花id:123456789012345678
转换为二进制后可以解析出:
雪花id因其简单高效的特性,已经成为分布式系统id生成的经典解决方案之一。
雪花id是twitter提出的一种分布式id生成算法,它生成64位的唯一id,通常包含时间戳、工作节点id和序列号。
在sql server中可以通过以下几种方式实现雪花id的生成:
-- 创建配置表
create table snowflakeconfig (
machineid bigint not null,
datacenterid bigint not null,
lasttimestamp bigint not null,
sequence bigint not null,
constraint pk_snowflakeconfig primary key (machineid, datacenterid)
);
-- 初始化配置 (机器id和数据中心id需要在每个节点上配置不同) insert into snowflakeconfig (machineid, datacenterid, lasttimestamp, sequence) values (1, 1, 0, 0);
-- 创建获取当前时间戳的函数
create function getcurrenttimestamp()
returns bigint
as
begin
declare @epoch datetime2 = '1970-01-01 00:00:00';
declare @now datetime2 = sysutcdatetime();
return cast(datediff_big(millisecond, @epoch, @now) as bigint);
end;
-- 创建等待下一毫秒的函数
create function tilnextmillis(@lasttimestamp bigint)
returns bigint
as
begin
declare @timestamp bigint;
set @timestamp = dbo.getcurrenttimestamp();
while @timestamp <= @lasttimestamp
begin
set @timestamp = dbo.getcurrenttimestamp();
end
return @timestamp;
end;
go
-- 创建计算幂的函数(替代位移操作)
create function poweroftwo(@exponent bigint)
returns bigint
as
begin
return cast(power(cast(2 as float), @exponent) as bigint);
end;
go
-- 创建生成雪花id的存储过程
create procedure generatesnowflakeid
@machineid bigint = 1,
@datacenterid bigint = 1,
@snowflakeid bigint output
as
begin
set nocount on;
-- 常量定义
declare @twepoch bigint = 1700058600000;
declare @machineidbits bigint = 5;
declare @datacenteridbits bigint = 5;
declare @sequencebits bigint = 12;
-- 使用power计算替代位移
declare @maxmachineid bigint = dbo.poweroftwo(@machineidbits) - 1;
declare @maxdatacenterid bigint = dbo.poweroftwo(@datacenteridbits) - 1;
declare @sequencemask bigint = dbo.poweroftwo(@sequencebits) - 1;
declare @machineidshift bigint = @sequencebits;
declare @datacenteridshift bigint = @sequencebits + @machineidbits;
declare @timestampleftshift bigint = @sequencebits + @machineidbits + @datacenteridbits;
-- 验证参数
if @machineid > @maxmachineid or @machineid < 0
begin
throw 50000, 'machineid can''t be greater than maxmachineid or less than 0', 1;
return;
end
if @datacenterid > @maxdatacenterid or @datacenterid < 0
begin
throw 50000, 'datacenterid can''t be greater than maxdatacenterid or less than 0', 1;
return;
end
-- 使用事务确保原子性
begin transaction;
begin try
declare @lasttimestamp bigint;
declare @sequence bigint;
declare @timestamp bigint;
-- 获取当前状态
select @lasttimestamp = lasttimestamp, @sequence = sequence
from snowflakeconfig with (updlock)
where machineid = @machineid and datacenterid = @datacenterid;
-- 获取当前时间戳
set @timestamp = dbo.getcurrenttimestamp();
-- 检查时钟回拨
if @timestamp < @lasttimestamp
begin
rollback transaction;
throw 50000, 'clock moved backwards. refusing to generate id', 1;
return;
end
-- 同一毫秒内生成多个id
if @lasttimestamp = @timestamp
begin
set @sequence = (@sequence + 1) & @sequencemask;
if @sequence = 0
begin
-- 序列耗尽,等待下一毫秒
set @timestamp = dbo.tilnextmillis(@lasttimestamp);
end
end
else
begin
set @sequence = 0;
end
-- 更新状态
update snowflakeconfig
set lasttimestamp = @timestamp,
sequence = @sequence
where machineid = @machineid and datacenterid = @datacenterid;
-- 生成id (使用乘法替代位移)
set @snowflakeid =
(@timestamp - @twepoch) * dbo.poweroftwo(@timestampleftshift) +
@datacenterid * dbo.poweroftwo(@datacenteridshift) +
@machineid * dbo.poweroftwo(@machineidshift) +
@sequence;
commit transaction;
end try
begin catch
rollback transaction;
throw;
end catch
end;
go
-- 使用存储过程版本 declare @id bigint; exec generatesnowflakeid @machineid = 1, @datacenterid = 1, @snowflakeid = @id output; select @id as snowflakeid;

到此这篇关于sqlserver中生成雪花id(snowflake id)的实现方法的文章就介绍到这了,更多相关sqlserver生成雪花id内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论