【Sql Server】在SQL Server中生成雪花ID(Snowflake ID)

大家好,我是全栈小5,欢迎来到《小5讲堂》。
这是《Sql Server》系列文章,每篇文章将以博主理解的角度展开讲解。
温馨提示:博主能力有限,理解水平有限,若有不对之处望指正!

在这里插入图片描述

目录

  • 前言
  • 认识雪花ID
    • 雪花ID的核心特点
    • 雪花ID的结构(64位)
    • 雪花ID的优势
    • 雪花ID的局限性
    • 雪花ID的应用场景
    • 示例ID解析
  • 生成雪花ID
    • 使用T-SQL函数实现
    • 查看效果
  • 文章推荐

前言

在我的印象中用到这个雪花ID比较少,可能是我接触的大型项目或者开源项目比较少,同时接触到中大型分布式也比较少,基本都是自研系统,用的是自增ID和GuidValue作为唯一编号。
最近项目上使用了一套第三方框架代码,使用了雪花ID作为表的唯一主键,并且之前表没有这个字段,需要进行表迁移的同时初始化雪花ID字段值。
因此,趁这次机会简单总结下雪花ID以及在Sql Server上如何生成雪花ID。

认识雪花ID

雪花ID是Twitter开发的一种分布式唯一ID生成算法,主要用于在分布式系统中生成全局唯一的ID标识符。它的名称来源于"自然界中没有两片完全相同的雪花"这一概念,象征着每个生成的ID都是独一无二的。

雪花ID的核心特点

  1. 全局唯一性:在分布式系统中生成的ID不会重复
  2. 时间有序性:ID按照时间顺序递增
  3. 高性能:本地生成,不依赖数据库等外部系统
  4. 可解析:ID中包含的信息可以被解析出来

雪花ID的结构(64位)

标准的雪花ID由以下三部分组成(共64位):

| 1位符号位 | 41位时间戳 | 10位工作节点ID | 12位序列号 |

具体分解:

  1. 符号位(1位):始终为0,保证ID为正数
  2. 时间戳(41位):毫秒级的时间戳,可以使用约69年
    • 通常从自定义纪元开始计算(如Twitter使用2010-11-04 01:42:54 UTC)
  3. 工作节点ID(10位)
    • 通常分为5位数据中心ID + 5位机器ID
    • 最多支持32个数据中心,每个数据中心32台机器
  4. 序列号(12位):同一毫秒内的序列号,支持每毫秒生成4096个ID

雪花ID的优势

  1. 分布式友好:不同节点可以独立生成ID而不需要协调
  2. 时间有序:生成的ID按时间递增,有利于数据库索引
  3. 高性能:本地生成,不依赖网络或数据库
  4. 信息丰富:ID本身包含时间、节点等信息

雪花ID的局限性

  1. 时钟依赖:严重依赖系统时钟,时钟回拨会导致ID重复
  2. 节点ID配置:需要手动或通过外部系统分配节点ID
  3. 时间耗尽:41位时间戳大约69年后会耗尽

雪花ID的应用场景

  1. 分布式系统主键生成
  2. 订单号、交易号等业务编号
  3. 日志跟踪ID
  4. 任何需要全局唯一且有序ID的场景

示例ID解析

假设一个雪花ID:123456789012345678

转换为二进制后可以解析出:

  • 时间戳部分:可以转换为具体的生成时间
  • 工作节点部分:知道是在哪个数据中心哪台机器生成的
  • 序列号部分:知道这是该毫秒内生成的第几个ID

雪花ID因其简单高效的特性,已经成为分布式系统ID生成的经典解决方案之一。

生成雪花ID

雪花ID是Twitter提出的一种分布式ID生成算法,它生成64位的唯一ID,通常包含时间戳、工作节点ID和序列号。
在SQL Server中可以通过以下几种方式实现雪花ID的生成:

使用T-SQL函数实现

-- 创建配置表
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
BEGINDECLARE @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
BEGINDECLARE @timestamp BIGINT;SET @timestamp = dbo.GetCurrentTimestamp();WHILE @timestamp <= @lastTimestampBEGINSET @timestamp = dbo.GetCurrentTimestamp();ENDRETURN @timestamp;
END;
GO
-- 创建计算幂的函数(替代位移操作)
CREATE FUNCTION PowerOfTwo(@exponent BIGINT)
RETURNS BIGINT
AS
BEGINRETURN 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
BEGINSET 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 < 0BEGINTHROW 50000, 'MachineId can''t be greater than maxMachineId or less than 0', 1;RETURN;ENDIF @DatacenterId > @MaxDatacenterId OR @DatacenterId < 0BEGINTHROW 50000, 'DatacenterId can''t be greater than maxDatacenterId or less than 0', 1;RETURN;END-- 使用事务确保原子性BEGIN TRANSACTION;BEGIN TRYDECLARE @LastTimestamp BIGINT;DECLARE @Sequence BIGINT;DECLARE @Timestamp BIGINT;-- 获取当前状态SELECT @LastTimestamp = LastTimestamp, @Sequence = SequenceFROM SnowflakeConfig WITH (UPDLOCK)WHERE MachineId = @MachineId AND DatacenterId = @DatacenterId;-- 获取当前时间戳SET @Timestamp = dbo.GetCurrentTimestamp();-- 检查时钟回拨IF @Timestamp < @LastTimestampBEGINROLLBACK TRANSACTION;THROW 50000, 'Clock moved backwards. Refusing to generate id', 1;RETURN;END-- 同一毫秒内生成多个IDIF @LastTimestamp = @TimestampBEGINSET @Sequence = (@Sequence + 1) & @SequenceMask;IF @Sequence = 0BEGIN-- 序列耗尽,等待下一毫秒SET @Timestamp = dbo.TilNextMillis(@LastTimestamp);ENDENDELSEBEGINSET @Sequence = 0;END-- 更新状态UPDATE SnowflakeConfigSET LastTimestamp = @Timestamp,Sequence = @SequenceWHERE 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 TRYBEGIN CATCHROLLBACK TRANSACTION;THROW;END CATCH
END;
GO

查看效果

-- 使用存储过程版本
DECLARE @Id BIGINT;
EXEC GenerateSnowflakeId @MachineId = 1, @DatacenterId = 1, @SnowflakeId = @Id OUTPUT;
SELECT @Id AS SnowflakeId;

在这里插入图片描述

文章推荐

【Sql Server】使用row_number over方式进行表分页,数据量达到五千多条记录后,查询变慢需要20多秒的解决方案

【Sql Server】随机查询一条表记录,并重重温回顾下自定义函数的封装和使用

【Sql Server】锁表如何解锁,模拟会话事务方式锁定一个表然后进行解锁

【Sql Server】通过Sql语句批量处理数据,使用变量且遍历数据进行逻辑处理

【新星计划回顾】第六篇学习计划-通过自定义函数和存储过程模拟MD5数据

【新星计划回顾】第四篇学习计划-自定义函数、存储过程、随机值知识点

【Sql Server】Update中的From语句,以及常见更新操作方式

【Sql server】假设有三个字段a,b,c 以a和b分组,如何查询a和b唯一,但是c不同的记录

【Sql Server】新手一分钟看懂在已有表基础上修改字段默认值和数据类型

总结:温故而知新,不同阶段重温知识点,会有不一样的认识和理解,博主将巩固一遍知识点,并以实践方式和大家分享,若能有所帮助和收获,这将是博主最大的创作动力和荣幸。也期待认识更多优秀新老博主。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/42426.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HarmonyOS NEXT——【鸿蒙原生应用加载Web页面】

鸿蒙客户端加载Web页面&#xff1a; 在鸿蒙原生应用中&#xff0c;我们需要使用前端页面做混合开发&#xff0c;方法之一是使用Web组件直接加载前端页面&#xff0c;其中WebView提供了一系列相关的方法适配鸿蒙原生与web之间的使用。 效果 web页面展示&#xff1a; Column()…

Spring Data审计利器:@LastModifiedDate详解!!!

&#x1f552; Spring Data审计利器&#xff1a;LastModifiedDate详解&#x1f525; &#x1f31f; 简介 在数据驱动的应用中&#xff0c;记录数据的最后修改时间是常见需求。Spring Data的LastModifiedDate注解让这一过程自动化成为可能&#xff01;本篇带你掌握它的核心用法…

循环神经网络(RNN)

循环神经网络&#xff08;RNN&#xff09; 循环神经网络&#xff08;Recurrent Neural Network&#xff0c;简称 RNN&#xff09;是一类用于处理序列数据的神经网络模型。与传统的前馈神经网络&#xff08;如多层感知机&#xff09;不同&#xff0c;RNN 具有反馈结构&#xff…

iOS rootless无根越狱检测方案

不同于安卓的开源生态&#xff0c;iOS一直秉承着安全性更高的闭源生态&#xff0c;系统中的硬件、软件和服务会经过严格审核和测试&#xff0c;来保障安全性与稳定性。 据FairGurd观察&#xff0c;虽然iOS系统具备一定的安全性&#xff0c;但并非没有漏洞&#xff0c;如市面上…

【React】基于 React+Tailwind 的 EmojiPicker 选择器组件

1.背景 React 写一个 EmojiPicker 组件&#xff0c;基于 emoji-mart 组件二次封装。支持添加自定义背景 、Emoji 图标选择&#xff01;并在页面上展示&#xff01; 2.技术栈 emoji-mart/data 、emoji-mart : emoji 图标库、元数据 tailwindcss: 原子化 CSS 样式库 antd : 组…

skynet.socket.limit 使用详解

目录 核心作用方法定义使用场景场景 1&#xff1a;限制接收缓冲区&#xff08;防御大包攻击&#xff09;场景 2&#xff1a;动态调整限制&#xff08;应对不同负载&#xff09; 底层机制注意事项完整示例&#xff1a;带流量控制的 Echo 服务总结 在 Skynet 框架中&#xff0c;s…

electron打包vue2项目流程

1&#xff0c;安装一个node vue2 的项目 2&#xff0c;安装electron&#xff1a; npm install electron -g//如果安装还是 特比慢 或 不想安装cnpn 淘宝镜像查看是否安装成功&#xff1a;electron -v 3&#xff0c;进入到项目目录&#xff1a;cd electron-demo 进入项目目录…

【面试八股】:常见的锁策略

常见的锁策略 synchronized &#xff08;标准库的锁不够你用了&#xff09;锁策略和 Java 不强相关&#xff0c;其他语言涉及到锁&#xff0c;也有这样的锁策略。 1. 悲观锁&#xff0c;乐观锁&#xff08;描述的加锁时遇到的场景&#xff09; 悲观锁&#xff1a;预测接下来…

【数据分享】基于联合国城市化程度框架的全球城市边界数据集(免费获取/Shp格式)

在全球城市化进程不断加快的今天&#xff0c;如何精准定义和测量“城市”成为关键问题。不同国家和机构采用不同的标准&#xff0c;导致全球城市化水平的统计结果存在较大差异。同时&#xff0c;由于数据来源分散、标准不统一&#xff0c;获取一套完整、可比的全球城市边界数据…

acwing 每日一题4888. 领导者

目录 题目简述&#xff1a; 思路梳理&#xff1a; 总代码&#xff1a; https://www.acwing.com/problem/content/description/4891/ 题目简述&#xff1a; 有两个品种的奶牛&#xff0c;分别为G和H&#xff0c;我们要在每个品种中各找一头牛当领导者&#xff0c;最后输出全…

在Windows下VSCodeSSH远程登录到Ubuntu

Window用VSCode通过SSH远程登录Ubuntu SSH 服务开启Windows远程登录 SSH 服务开启 首先要确保 Ubuntu 的 SSH 服务开启了&#xff0c;开启 Ubuntu 的 SSH 服务以后我们就可以在 Windwos 下使用终端软件登陆到 Ubuntu 开启 SSH sudo apt-get install openssh-serverWindows远…

软件性能测试中的“假阳性”陷阱

软件性能测试中的“假阳性”陷阱主要表现为错误警报频繁、资源浪费严重、测试可信度降低。其中&#xff0c;错误警报频繁是最常见且最严重的问题之一&#xff0c;“假阳性”现象会导致开发团队在解决不存在的问题上花费大量时间。据行业调查显示&#xff0c;超过30%的性能优化成…

AwesomeQt分享3(含源码)

AwesomeQt 这个项目包含了多个Qt组件的使用示例&#xff0c;旨在展示Qt各种强大功能的实现方式。 源码分享 github: awesome_Qtgitee: 后续同步 项目进度 QCustomPlot曲线控件示例 支持排序和筛选的列表控件示例 支持排序和筛选的表格控件示例 属性表示例 Dock窗口示例 自绘…

如何验证极端工况下的系统可靠性?

验证极端工况下系统可靠性的方法主要包括设计极限测试、环境应力筛选&#xff08;ESS&#xff09;、可靠性预测与建模。其中&#xff0c;设计极限测试最为关键&#xff0c;通过在试验中施加超过预期使用条件的应力&#xff0c;可以有效评估系统的真实承受能力和潜在弱点。这类测…

[计算机网络]网络I/O模型

欢迎来到啾啾的博客&#x1f431;。 这是一个致力于构建完善的Java程序员知识体系的博客&#x1f4da;&#xff0c;记录学习的点滴&#xff0c;分享工作的思考、实用的技巧&#xff0c;偶尔也分享一些杂谈&#x1f4ac;。 欢迎评论交流&#xff0c;感谢您的阅读&#x1f604;。…

MyBaitis-Plus 使用动态表名 selectPage 不生效

在使用 MyBatis-Plus 时&#xff0c;采用动态表名策略后&#xff0c;selectPage 方法无法正常生效。 MyBatis-Plus动态表名插件配置MyBatis-Plus动态表名失效原因MyBatis-Plus动态表名失效解决办法 MyBatis-Plus动态表名插件配置 以下是我项目中 MyBatis - Plus 的插件配置&am…

C语言基础—构造类型

数据类型 1.基本类型/基础类型 整型 短整型&#xff1a;short[int] --2字节 基本整型&#xff1a;int --4字节 长整型&#xff1a;long[int] --32位4字节/64位8字节 长长整型&#xff1a;long long [int] &#xff08;C99&#xff09; 注意&#xff1a;以上类型又都分为sig…

交流电机类型及其控制技术

交流电机可分为同步电机和异步电机两大种类&#xff0c;如果电机转子的转速与定子旋转磁场的转速相等&#xff0c;转子与定子旋转磁场在空间同步地旋转&#xff0c;这种电机就称为同步电机。如果电机转子的转速不等于定子旋转磁场的转速&#xff0c;转子与定子旋转磁场在空间旋…

「HTML5+Canvas实战」星际空战游戏开发 - 纯前端实现 源码即开即用【附演示视频】

纯前端实现星际空战游戏【简易版】 博主上次分享的简易版飞机大战收到了不少建议,今天再给大家来一波福利!带来全新升级的飞机大战进阶版!不仅拥有更丰富的游戏机制和更精美的游戏画面,还加入了超燃的BOSS战斗系统。源码完全免费开放,拿来即用无门槛,欢迎感兴趣的小伙伴…

7-项目负责人-添加产品

点击一个项目集&#xff0c;进入项目集的页面。可以进行产品、项目、人员和干系人的管理。 点击“添加产品”&#xff0c;为该项目集添加关联产品。一个项目集可以关联多个产品。还可以通过“产品线”管理一些列产品。 产品。