在 MySQL 中,使用 UUID 作為主鍵 在大表中可能會導致性能問題,尤其是在插入和修改數(shù)據(jù)時效率較低。以下是詳細的原因分析,以及為什么修改數(shù)據(jù)會導致索引刷新,以及字符主鍵為什么效率較低。
1. UUID 作為主鍵的問題
(1)UUID 的特性
- UUID 是一個 128 位的字符串,通常表示為 36 個字符(例如:
550e8400-e29b-41d4-a716-446655440000
)。 - UUID 是全局唯一的,適合分布式系統(tǒng)中生成唯一標識。
(2)UUID 作為主鍵的缺點
1. 索引效率低
- 索引大小:UUID 是字符串類型,占用空間較大(36 字節(jié)),而整型主鍵(如
BIGINT
)僅占用 8 字節(jié)。索引越大,存儲和查詢的效率越低。 - 索引分裂:UUID 是無序的,插入新數(shù)據(jù)時,可能會導致索引樹頻繁分裂和重新平衡,影響性能。
2. 插入性能差
- 隨機性:UUID 是無序的,每次插入新數(shù)據(jù)時,新記錄可能會插入到索引樹的任意位置,導致索引樹頻繁調(diào)整。
- 頁分裂:InnoDB 存儲引擎使用 B+ 樹作為索引結(jié)構(gòu),隨機插入會導致頁分裂,增加磁盤 I/O 操作。
3. 查詢性能差
- 比較效率低:字符串比較比整型比較慢,尤其是在大表中,查詢性能會顯著下降。
- 索引掃描范圍大:UUID 索引占用的空間大,導致索引掃描的范圍更大,查詢效率降低。
2. 修改數(shù)據(jù)導致索引刷新的原因
(1)索引的作用
- 索引是為了加速查詢而創(chuàng)建的數(shù)據(jù)結(jié)構(gòu)(如 B+ 樹)。
- 當數(shù)據(jù)被修改時,索引也需要同步更新,以保持數(shù)據(jù)的一致性。
(2)修改數(shù)據(jù)對索引的影響
- 如果修改了主鍵值,MySQL 需要刪除舊的主鍵索引記錄,并插入新的主鍵索引記錄。
- 這個過程會導致索引樹的調(diào)整,增加磁盤 I/O 操作。
- 如果修改的列是索引列(如唯一索引、普通索引),MySQL 需要更新對應的索引記錄。
(3)UUID 主鍵的額外開銷
- 由于 UUID 是無序的,修改主鍵值時,新值可能會插入到索引樹的不同位置,導致索引樹頻繁調(diào)整。
- 相比于有序的主鍵(如自增 ID),UUID 主鍵的修改操作代價更高。
3. 字符主鍵導致效率降低的原因
(1)存儲空間大
- 字符主鍵(如 UUID)占用的存儲空間比整型主鍵大。
- 索引的大小直接影響查詢性能,索引越大,查詢時需要的磁盤 I/O 操作越多。
(2)比較效率低
- 字符串比較比整型比較慢,尤其是在大表中,查詢性能會顯著下降。
- 例如,
WHERE id = '550e8400-e29b-41d4-a716-446655440000'
的效率低于 WHERE id = 12345
。
(3)索引分裂
- 字符主鍵通常是無序的,插入新數(shù)據(jù)時,可能會導致索引樹頻繁分裂和重新平衡,影響性能。
4. 如何優(yōu)化 UUID 主鍵的性能
(1)使用有序 UUID
- 使用有序 UUID(如
UUIDv7
),減少索引分裂和頁分裂。 - 有序 UUID 的生成方式可以基于時間戳,保證插入順序。
(2)將 UUID 存儲為二進制
將 UUID 存儲為 BINARY(16)
而不是 CHAR(36)
,減少存儲空間。
sql 代碼解讀復制代碼CREATETABLEusers (
idBINARY(16) PRIMARY KEY,
nameVARCHAR(255)
);
(3)使用自增主鍵 + UUID
使用自增主鍵作為物理主鍵,UUID 作為邏輯主鍵。
sql 代碼解讀復制代碼CREATETABLEusers (
idBIGINT AUTO_INCREMENT PRIMARY KEY,
uuidCHAR(36) UNIQUE,
nameVARCHAR(255)
);
(4)分區(qū)表
- 對大表進行分區(qū),減少單個索引樹的大小,提高查詢性能。
Summary
- 修改數(shù)據(jù)時,索引需要頻繁刷新,導致性能下降。
該文章在 2025/4/27 16:09:05 編輯過