" />

欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SQLServer中生成雪花ID(Snowflake?ID)的實(shí)現(xiàn)方法

 更新時(shí)間:2025年08月08日 08:28:06   作者:全棧小5  
這篇文章主要介紹了在SQL?Server中生成雪花ID(Snowflake?ID)的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

前言

在我的印象中用到這個(gè)雪花ID比較少,可能是我接觸的大型項(xiàng)目或者開(kāi)源項(xiàng)目比較少,同時(shí)接觸到中大型分布式也比較少,基本都是自研系統(tǒng),用的是自增ID和GuidValue作為唯一編號(hào)。
最近項(xiàng)目上使用了一套第三方框架代碼,使用了雪花ID作為表的唯一主鍵,并且之前表沒(méi)有這個(gè)字段,需要進(jìn)行表遷移的同時(shí)初始化雪花ID字段值。
因此,趁這次機(jī)會(huì)簡(jiǎn)單總結(jié)下雪花ID以及在Sql Server上如何生成雪花ID。

認(rèn)識(shí)雪花ID

雪花ID是Twitter開(kāi)發(fā)的一種分布式唯一ID生成算法,主要用于在分布式系統(tǒng)中生成全局唯一的ID標(biāo)識(shí)符。它的名稱來(lái)源于"自然界中沒(méi)有兩片完全相同的雪花"這一概念,象征著每個(gè)生成的ID都是獨(dú)一無(wú)二的。

雪花ID的核心特點(diǎn)

  1. 全局唯一性:在分布式系統(tǒng)中生成的ID不會(huì)重復(fù)
  2. 時(shí)間有序性:ID按照時(shí)間順序遞增
  3. 高性能:本地生成,不依賴數(shù)據(jù)庫(kù)等外部系統(tǒng)
  4. 可解析:ID中包含的信息可以被解析出來(lái)

雪花ID的結(jié)構(gòu)(64位)

標(biāo)準(zhǔn)的雪花ID由以下三部分組成(共64位):

| 1位符號(hào)位 | 41位時(shí)間戳 | 10位工作節(jié)點(diǎn)ID | 12位序列號(hào) |

具體分解:

  1. 符號(hào)位(1位):始終為0,保證ID為正數(shù)
  2. 時(shí)間戳(41位):毫秒級(jí)的時(shí)間戳,可以使用約69年
    • 通常從自定義紀(jì)元開(kāi)始計(jì)算(如Twitter使用2010-11-04 01:42:54 UTC)
  3. 工作節(jié)點(diǎn)ID(10位)
    • 通常分為5位數(shù)據(jù)中心ID + 5位機(jī)器ID
    • 最多支持32個(gè)數(shù)據(jù)中心,每個(gè)數(shù)據(jù)中心32臺(tái)機(jī)器
  4. 序列號(hào)(12位):同一毫秒內(nèi)的序列號(hào),支持每毫秒生成4096個(gè)ID

雪花ID的優(yōu)勢(shì)

  1. 分布式友好:不同節(jié)點(diǎn)可以獨(dú)立生成ID而不需要協(xié)調(diào)
  2. 時(shí)間有序:生成的ID按時(shí)間遞增,有利于數(shù)據(jù)庫(kù)索引
  3. 高性能:本地生成,不依賴網(wǎng)絡(luò)或數(shù)據(jù)庫(kù)
  4. 信息豐富:ID本身包含時(shí)間、節(jié)點(diǎn)等信息

雪花ID的局限性

  1. 時(shí)鐘依賴:嚴(yán)重依賴系統(tǒng)時(shí)鐘,時(shí)鐘回?fù)軙?huì)導(dǎo)致ID重復(fù)
  2. 節(jié)點(diǎn)ID配置:需要手動(dòng)或通過(guò)外部系統(tǒng)分配節(jié)點(diǎn)ID
  3. 時(shí)間耗盡:41位時(shí)間戳大約69年后會(huì)耗盡

雪花ID的應(yīng)用場(chǎng)景

  1. 分布式系統(tǒng)主鍵生成
  2. 訂單號(hào)、交易號(hào)等業(yè)務(wù)編號(hào)
  3. 日志跟蹤ID
  4. 任何需要全局唯一且有序ID的場(chǎng)景

示例ID解析

假設(shè)一個(gè)雪花ID:123456789012345678

轉(zhuǎn)換為二進(jìn)制后可以解析出:

  • 時(shí)間戳部分:可以轉(zhuǎn)換為具體的生成時(shí)間
  • 工作節(jié)點(diǎn)部分:知道是在哪個(gè)數(shù)據(jù)中心哪臺(tái)機(jī)器生成的
  • 序列號(hào)部分:知道這是該毫秒內(nèi)生成的第幾個(gè)ID

雪花ID因其簡(jiǎn)單高效的特性,已經(jīng)成為分布式系統(tǒng)ID生成的經(jīng)典解決方案之一。

生成雪花ID

雪花ID是Twitter提出的一種分布式ID生成算法,它生成64位的唯一ID,通常包含時(shí)間戳、工作節(jié)點(diǎn)ID和序列號(hào)。
在SQL Server中可以通過(guò)以下幾種方式實(shí)現(xiàn)雪花ID的生成:

使用T-SQL函數(shù)實(shí)現(xiàn)

-- 創(chuàng)建配置表
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)
);
-- 初始化配置 (機(jī)器ID和數(shù)據(jù)中心ID需要在每個(gè)節(jié)點(diǎn)上配置不同)
INSERT INTO SnowflakeConfig (MachineId, DatacenterId, LastTimestamp, Sequence)
VALUES (1, 1, 0, 0);
-- 創(chuàng)建獲取當(dāng)前時(shí)間戳的函數(shù)
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;
-- 創(chuàng)建等待下一毫秒的函數(shù)
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
-- 創(chuàng)建計(jì)算冪的函數(shù)(替代位移操作)
CREATE FUNCTION PowerOfTwo(@exponent BIGINT)
RETURNS BIGINT
AS
BEGIN
    RETURN CAST(POWER(CAST(2 AS FLOAT), @exponent) AS BIGINT);
END;
GO
-- 創(chuàng)建生成雪花ID的存儲(chǔ)過(guò)程
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計(jì)算替代位移
    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;
    
    -- 驗(yàn)證參數(shù)
    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
    
    -- 使用事務(wù)確保原子性
    BEGIN TRANSACTION;
    
    BEGIN TRY
        DECLARE @LastTimestamp BIGINT;
        DECLARE @Sequence BIGINT;
        DECLARE @Timestamp BIGINT;
        
        -- 獲取當(dāng)前狀態(tài)
        SELECT @LastTimestamp = LastTimestamp, @Sequence = Sequence
        FROM SnowflakeConfig WITH (UPDLOCK)
        WHERE MachineId = @MachineId AND DatacenterId = @DatacenterId;
        
        -- 獲取當(dāng)前時(shí)間戳
        SET @Timestamp = dbo.GetCurrentTimestamp();
        
        -- 檢查時(shí)鐘回?fù)?
        IF @Timestamp < @LastTimestamp
        BEGIN
            ROLLBACK TRANSACTION;
            THROW 50000, 'Clock moved backwards. Refusing to generate id', 1;
            RETURN;
        END
        
        -- 同一毫秒內(nèi)生成多個(gè)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
        
        -- 更新?tīng)顟B(tài)
        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

查看效果

-- 使用存儲(chǔ)過(guò)程版本
DECLARE @Id BIGINT;
EXEC GenerateSnowflakeId @MachineId = 1, @DatacenterId = 1, @SnowflakeId = @Id OUTPUT;
SELECT @Id AS SnowflakeId;

到此這篇關(guān)于SQLServer中生成雪花ID(Snowflake ID)的實(shí)現(xiàn)方法的文章就介紹到這了,更多相關(guān)sqlserver生成雪花id內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論