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