這個周末,尼克博士與我們分享了一篇寫得很好的文章,討論了自動遞增(串行)密鑰的缺點和一種替代方法。在討論本文時,出現了一個問題:如何在應用程序中使用 UUID 鍵,以及在 PostgreSQL 中如何使用 UUID 鍵。PostgreSQL 開箱即用定義了一個 UUID數據類型,這是一個很好的開始。然后我們有三個選項來生成 UUID,
在我們的應用程序中生成它們會很好地工作,這是一種很好的方法,除非您希望數據庫為您自動處理這些創建,而這通常是我們的觀點所在。
只有當您確實需要它提供的功能時才使用uid-ossp,如果您只需要生成和索引它們,那么您就不需要 uid-ossp。(更新:見下文)。要在數據庫中生成 UUID,一個簡單的起點是使用 pgcrypto 擴展中的 gen_random_uuid() 函數。
那么我們如何使用這個函數呢?首先我們需要在數據庫中創建擴展名,
CREATE EXTENSION pgcrypto;
這是加載預編譯共享庫代碼的方式,這些代碼將功能添加到 PostgreSQL 數據庫中。
特別注意,必須為希望在其中使用擴展的每個數據庫創建(加載)一個擴展。當它被加載到數據庫服務器的運行實例中,重啟服務才能生效。
還要注意,如果您已經將數據庫從一個服務器轉儲並恢復到另一個正在運行的實例,那么根據轉儲/恢復的方法,您可能需要在恢復之后將其加載到這個新實例中。
使用下面的 SQL 語句,就可以生成一個 UUID
SELECT gen_random_uuid();
返回 UUID 數據類型。
讓我們用 UUID 主鍵創建一個表,看看我們如何使用gen_random_uuid()函數來為我們填充標識,
CREATE SCHEMA IF NOT EXISTS snw;
CREATE TABLE snw.contacts(
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT,
email TEXT
);
現在我們可以在新建的 Stark & Wayne 聯系人表中添加條目,
INSERT INTO snw.contacts (name,email) VALUES
('Dr Nic Williams','drnic'),
('Brian Mattal','brian'),
('Wayne E. Seguin','wayneeseguin'),
('Long Nguyen','long'),
('Bill Chapman','bill'),
('Chris Weibel','chris'),
('Jeremey Budnack','jrbudnack'),
('Ruben Koster','rkoster'),
('Jamie Van Dyke','jamie'),
('Quintessence Anx','qanx'),
('McGowan','mcg'),
('高,秀嬌 (XJ)','xj'),
('Geoff Franks','geoff'),
('Van Nguyen','vnguyen'),
('John Longanecker','jlonganecker')
;
INSERT 0 15
現在我們來看看我們的表格
SELECT * FROM snw.contacts;
id | name | email
--------------------------------------+------------------+---------------
0d60a85e-0b90-4482-a14c-108aea2557aa | Dr Nic Williams | drnic
39240e9f-ae09-4e95-9fd0-a712035c8ad7 | Brian Mattal | brian
9e4de779-d6a0-44bc-a531-20cdb97178d2 | Wayne E. Seguin | wayneeseguin
66a45c1b-19af-4ab5-8747-1b0e2d79339d | Long Nguyen | long
bc8250bb-f7eb-4adc-925c-2af315cc4a55 | Bill Chapman | bill
200393bc-8aaa-45a8-9093-80c4792348cd | Chris Weibel | chris
cd881764-bea1-4249-b86d-f8fb8182eec1 | Jeremey Budnack | jrbudnack
970972dd-dce8-4c65-a85b-63735ada0fc9 | Ruben Koster | rkoster
1c225a3a-2c70-4d95-b87f-f086cbd20366 | Jamie Van Dyke | jamie
9f0bb16e-fc25-47f3-b60a-635b6224225a | Quintessence Anx | qanx
9788c636-936e-4dd6-b9d5-f340329142bd | McGowan | mcg
3d8b664f-ef5f-4587-a45c-f2991a1fc029 | 高,秀嬌 (XJ) | xj
f618f5a8-380e-44fb-9b4e-b3286f29dcc8 | Geoff Franks | geoff
35cb41dd-3edb-4483-a1fe-fc315243d2f8 | Van Nguyen | vnguyen
74b37cd4-75aa-4871-b17b-a5160428e589 | John Longanecker | jlonganecker
(15 rows)
我們看到每一行都有一個 UUID id字段,它是自動為我們生成的主鍵。
討論
@drewblas(謝謝Drew!)指出,使用 pgcrypto 中的 gen_random_uuid() 對表在磁盤上的鍵空間碎片有負面影響。Drew告訴我們:
Random產生非常片段的插入,這會破壞表。使用 uuid_generate_v1mc() [代替]…鍵是seq,因為它們是基於時間的。所以所有插入都指向同一個數據頁,沒有隨機 io。
這是有道理的,由於隨機概率分布的鍵,它應該是碎片。但是,這種碎片對數據庫系統本身的效率不是很好。為了獲得較低的使用 UUID 的好處主鍵用於分裂也許指出了最好使用 uuid_generate_v1mc() 下面從 uuid-ossp 擴展,因為它使用一個基於時間的 seq 算法中可以讀到 postgresql文檔。