前陣子的「為資料庫提案新的 UUID 格式」這邊提到了有人提案要增加新的 UUID 格式,Percona 的老大 Peter Zaitsev 在 Twitter 上貼了「UUIDs are Popular, but Bad for Performance — Let’s Discuss」這篇在 2019 年時他們家的文章,題到了 MySQL 使用 UUID 當作 Primary Key 的事情:
UUIDs are Popular, but Bad for Performance — Let’s Discuss
https://t.co/2ulSGPB77L— Peter Zaitsev (@PeterZaitsev) August 21, 2021
要注意的是這篇文章沒有要從頭解釋 UUID 對於 Primary Key 的壞處,如果你想要先了解的話,在這篇文章的開頭給了一堆其他文章的連結,裡面就有討論過了。
這篇主要是在討論,如果硬要用 UUID 當 Primary Key 時,可以有什麼方法降低對 InnoDB 的衝擊,剛好回應最近的提案。
開頭還是先花了一些篇幅大概講一下 UUID 的種類,然後在「What is so Wrong with UUID Values?」這邊提到了字串比較的差異,如果 UUID 是到最後一碼才不同的話 (這邊是跑 df878007-80da-11e9-93dd-00163e000002 與 df878007-80da-11e9-93dd-00163e000003 與比較一億次):
1 row in set (27.67 sec)
但如果是一開始就不同的話 (這邊是選擇 df878007-80da-11e9-93dd-00163e000002 與 ef878007-80da-11e9-93dd-00163e000003) 會快很多:
1 row in set (2.45 sec)
但如果與數字相比的話 (這邊是 2=3
這樣的條件去比):
1 row in set (0.96 sec)
可以看數字在這邊的優勢,另外也是在說明,如果你用的是 time-based ordering 的 UUID,要考慮會遇到這個可能會發生的效能問題。
再來是玩 UUID 的三種不同的儲存方式對於寫入效能的差異,分別是 CHAR(36)
(32 bytes 的 hex 加上四個 -
)、base64
(用 CHAR(22)
存) 與 BINARY(16)
,可以看出來 BINARY(16)
因為佔用空間比較小的關係,是可以高速寫入持續最久的,再來是 base64
,最差的是 CHAR(36)
:
後面給了兩個 workaround,第一個算是定義了另外一種產生 128 bits 的方式,第二個則是想辦法把 UUID 對應到數字。
這在 MySQL 的環境裡面算是被討論的很久的主題了。(我猜在 PostgreSQL 應該也是,不過 PostgreSQL 的社群沒跟那麼久...)