在分散式系統、分庫分表、跨資料庫遷移等場景下,需要能夠在全局範圍內唯一標識記錄的 ID。MySQL 原生 AUTO_INCREMENT 僅在單表內唯一,無法滿足全局唯一需求。本文系統梳理五大主流方案,並給出選型建議。
SELECT UUID(); -- 36 字元字串,含連字號,基於時間+MAC+隨機數
SELECT UUID_SHORT(); -- 64 位無符號整數,基於 server_id + 時間 + 序列,較短
UUID_SHORT() 需確保 server_id 全局唯一。-- 主庫 1
SET @@auto_increment_increment=2;
SET @@auto_increment_offset=1; -- 產生 1,3,5,7...
-- 主庫 2
SET @@auto_increment_increment=2;
SET @@auto_increment_offset=2; -- 產生 2,4,6,8...
結構:1bit 符號位 | 41bit 毫秒時間戳 | 10bit 機器/節點 ID | 12bit 序列號
-- MySQL 函數實現範例 (需 5.7+ 支援)
CREATE FUNCTION snowflake_id() RETURNS BIGINT DETERMINISTIC
BEGIN
DECLARE epoch BIGINT DEFAULT 1609459200000; -- 2021-01-01
DECLARE node_id INT DEFAULT 1; -- 需部署時分配唯一
DECLARE seq INT DEFAULT 0;
DECLARE last_ts BIGINT DEFAULT 0;
-- 實際生產建議在應用層(Java/Go/PHP)實現,避免 DB 鎖競爭
RETURN (UNIX_TIMESTAMP(NOW(3))*1000 - epoch) << 22 | node_id << 12 | seq;
END
CREATE TABLE id_segment (biz_tag VARCHAR(128), max_id BIGINT, step INT, version INT);UPDATE id_segment SET max_id = max_id + step WHERE biz_tag = 'order' AND version = old_version;-- 儲存為 16 字節 BINARY(16),節省 50% 空間,索引效能優於 CHAR(36)
INSERT INTO t(id, data) VALUES (UUID_TO_BIN(UUID()), 'test');
SELECT BIN_TO_UUID(id) FROM t;
UUID_TO_BIN(UUID(), 1) 將時間位移至高位,改善索引局部性。| 場景 | 推薦方案 | 核心理由 |
|---|---|---|
| 單體應用、單表、低併發 | AUTO_INCREMENT | 最簡單、整數索引最優 |
| 微服務、分庫分表、中等併發 | Snowflake (應用層) | 去中心化、趨勢遞增、含時間語義 |
| 高併發、多業務線、需運維友好 | 號段模式 | DB 壓力最小、批次發號、易監控 |
| 異構系統整合、離線數據融合 | UUID / UUID_TO_BIN | 全球唯一、無協調、8.0 索引優化 |
最佳實踐建議: 核心交易鏈路優先使用「號段模式」或「應用層 Snowflake」;日誌/審計/非核心表可用
UUID_TO_BIN(UUID(), 1);嚴禁在高寫入表直接使用標準UUID()作為主鍵。