傳統設計常以業務欄位(單號、商品碼)或多欄位組合作為主鍵,隨著主從表層級加深,引發四大問題:
為每個資料表新增一個無業務含義的數值型主鍵(如 U_ID BIGINT),作為唯一識別碼;業務唯一性改由 UNIQUE 約束/索引 保證。
CREATE TABLE T_PK_DEMO (
U_ID BIGINT NOT NULL, -- 代理鍵
COL_OTHER VARCHAR(20) NOT NULL, -- 業務欄位
CONSTRAINT PK_T_PK_DEMO PRIMARY KEY NONCLUSTERED (U_ID),
CONSTRAINT UQ_T_PK_DEMO UNIQUE NONCLUSTERED (COL_OTHER) -- 業務唯一性
);
| 痛點 | 說明 |
|---|---|
| 完全由系統控制 | 使用者無法指定/修改值,測試與資料修補極不便 |
| 複寫/訂閱麻煩 | 身分識別欄位在合併式複寫需特殊處理 |
| 資料還原困難 | 部分還原時自增值易衝突 |
| 插入後才能取值 | 需額外 SCOPE_IDENTITY() 往返 |
CREATE TABLE T_DB_SEQ (
SEQ_NAME VARCHAR(50) NOT NULL,
SEQ_OWNER VARCHAR(50) NOT NULL DEFAULT 'DBO',
SEQ_CURRENT BIGINT NOT NULL DEFAULT 0,
SEQ_MIN BIGINT NOT NULL DEFAULT 0,
SEQ_MAX BIGINT NOT NULL DEFAULT 0,
SEQ_STEP INT NOT NULL DEFAULT 1,
IF_CYCLE INT NOT NULL DEFAULT 0,
CONSTRAINT PK_T_DB_SEQ PRIMARY KEY CLUSTERED (SEQ_NAME, SEQ_OWNER)
);
F_create_SEQ(@name):建立序列F_GET_NEXT_SEQ_VAL(@name):取得下一值(含並發鎖定保護)F_GET_SEQ_CUR_VAL(@name):取得目前值F_SET_SEQ_VAL(@name, @val):設定值F_DEL_SEQ(@name):刪除序列F_SEQ_exists(@name):檢查存在性CREATE TABLE T_PK_DEMO_C (
U_ID BIGINT NOT NULL,
COL_OTHER VARCHAR(20) NOT NULL,
P_ID BIGINT NOT NULL, -- 父表代理鍵
CONSTRAINT PK_T_PK_DEMO_C PRIMARY KEY NONCLUSTERED (U_ID),
CONSTRAINT FK_T_PK_DEMO_C FOREIGN KEY (P_ID)
REFERENCES T_PK_DEMO(U_ID) ON DELETE CASCADE
);
有了單一數值型主鍵,配合 ROW_NUMBER() OVER (ORDER BY U_ID) 或 OFFSET/FETCH,分頁查詢變得簡單高效,不再受困於多欄位排序與游標邏輯。