邏輯資料庫設計 需要ID 談主鍵Id

2021-09-06 09:59:51 字數 3316 閱讀 9011

本文的目標就是要確認那些使用了主鍵,卻混淆了主鍵的本質而造成的一種反模式。

每個了解資料庫設計的人都知道,主鍵對於一張表來說是乙個很重要,甚至必需的部分。這確實是事實,主鍵是好的資料庫設計的一部分。主鍵是資料庫確保資料行在整張表唯一性的保障。它是定位到一條記錄並且確保不會重複儲存的邏輯機制。主鍵也同時可以被外來鍵引用來建立表與表之間的關係。

難點是選擇那一列作為主鍵。大多數表中的每個屬性值都有可能被很多行使用。例如姓名,電子郵件位址等等都不能保證不會重複。

在這樣的表中,需要引入乙個對於表的域模型無意義的新列來儲存乙個偽值。這一列被用作這張表的主鍵,從而通過它來確定表中的一條記錄,即便其他的列允許出現適當的重複項。這種型別的主鍵列我們通常稱其為偽主鍵或者**鍵。

大多數資料庫提供一種和當前處理事務無關的底層方案,來確保每次都能生成全域性唯一的乙個整數作為偽主鍵,即使客戶端此時正發起併發操作。

主鍵存在的作用:

1、確保一張表中的資料不會出現重複行。

2、在查詢中引用單獨的一行記錄。

3、支援外來鍵。

(1)、主鍵的列名都叫做id;

(2)、資料型別是32位或者64位的整數

(3)、主鍵的值是自動生成來確保唯一的。

在每張表中都存在乙個叫做id的列是如此地平常,甚至id已經成為了主鍵的同義詞。很多程式設計師在一開始學習sql時就被灌輸了錯誤的概念。認為每張表都要增加一列id,這顯然太過於隨意。

1、冗餘鍵值

2、允許重複項

乙個組合鍵包含了多個不同的列,組合鍵的典型場景就是想上節中亂穿馬路中的contact表。主鍵需要確保乙個給定的product_id和account_id的組合在整張表中只能出現一次,雖然同乙個值可能在很多不同的配對出現。

然而,當你使用了id這一列作為主鍵,約束就不是account_id和product_id的組合必須唯一了。當你用這張交叉表去查詢account_id和product_id的關係時,重複項會意料之外的結果。要確保沒有重複項,你可以在id之外,額外宣告另外兩列需要乙個unique約束。但是當你在account_id和product_id這兩列上應用了唯一性約束,id這一列就會變成了多餘的列。它已經背離了主鍵的初衷了。

3、關鍵字意義不明確

id這個詞是如此地普通,完全無法表達更深沉的意思,特別是在你做兩張表連線查詢,而他們都有乙個叫做id的主鍵時。

select*  

from accout asa  

join bug b on (b.toid = a.id)

這種查詢必須在查詢時指定列別名,否則其中的乙個id列會覆蓋掉另一列的id的值。

同時有兩張表有相同的id列的情況下也不能夠使用using關鍵字。

比如:sql支援一種簡潔的表示式來表示兩張表聯結(using)。如果兩張表有同樣的列名,就可以用如下的表示式來重寫上面的需求。

select

*from account join bug using(bug_id);  --

乙個主鍵,乙個外來鍵。

然而,如果所有的表都要求定義乙個叫做id的偽主鍵,那麼將不能使用這種簡寫方式。 

4、使用組合鍵

一些開發人員覺得組合鍵太難使用,如果要比較兩個鍵值,必須比較其包含的所有列的值;乙個引用組合鍵的外來鍵,其本身也必須是乙個組合外來鍵。此外,使用組合鍵需要打更多的字。其實這是不對的。組合鍵的適當的時候是應該被使用的。

1、我覺得這張表不需要主鍵。

這麼說的人一定是誤解了「主鍵」和「偽主鍵」的含義,每張表都必須要有乙個主鍵,這個是毫無疑問的。實際上可能這個人需要的是乙個組合鍵,或者乙個更自然的列名來做主鍵。

2、我怎麼能在多對多的表中儲存重複的項?

在乙個對多對關係的交叉表中需要宣告乙個主鍵約束。或者至少需要有乙個針對那些被引用作為外來鍵的唯一約束。

使用偽主鍵,或者通過自動增長的整型的機制本身沒有什麼錯誤,但不是每張表都需要乙個偽主鍵,更沒有必要將每個偽主鍵都定義成id。

對於太長而不方便實現的自然鍵來說,偽主鍵是乙個很好的代替品。比如在乙個記錄檔案系統的所有檔案屬性的表中,檔案路徑是乙個很好的自然鍵,但對乙個字串列做索引的開銷會很大。

主鍵是約束而非資料型別。你可以定義任意列或任意多個的列作為主鍵。只要其資料型別支援索引。另外在此必須要補充的是,在sqlserver中,主鍵和聚集索引並沒必然的關係。sqlserver只是預設將聚集索引建在主鍵上,實際上你完全可以將聚集索引手動定義到非主鍵列。

1、為主鍵選擇更有意義的名稱

比如為product這張表的主鍵應該叫做product_id。

2、外來鍵應該盡可能地和所引用的列使用相同的名稱,這通常意味著:乙個主鍵的名稱應該在整個資料庫的設計中唯一;任意兩張表都不應該使用相同的名稱來定義主鍵,除非其中之一引用了另外乙個作為外來鍵。然而凡是都有例外,又是外來鍵的名稱需要和其所引用的主鍵區分開,從而使的它們之間的引用關係表現得更加清晰。

比如在一張外來鍵表中將外來鍵宣告為create_by(由誰建立)。  

規則自然鍵**鍵

主鍵必須唯一的識別每一記錄

但與輸入和人為錯誤有關

系統自生成的資料是唯一的

乙個記錄的主鍵不能為空

只有資料可知時才能輸入記錄

當記錄生成時才被系統建立

當生成記錄時,主鍵的值必須存在

只有資料可知時才能輸入記錄

當記錄生成時才被系統建立當記錄生成時才被系統建立

主鍵必須保持穩定——你不能更改主鍵的域

自然鍵與一些商業規則和其他外部影響有關

**鍵對程式功能和資料保持中立

主鍵必須簡潔,不要包含過分的屬性

乙個自然鍵可以包含多個域

**鍵只能包含多個域

主鍵的值不能改變

自然鍵通常改變

**鍵通常不更改

如果你的表中包含一列能夠確保唯

一、非空以及能夠用來定位一條記錄,就別僅僅因為傳統而覺得有必要再加上乙個偽主鍵。

實踐證明,一張表中的每一列都在最初的設計之後遭遇改變是很正常的事情。資料庫的設計趨向於在整個專案的宣告週期中不斷地調整和優化,並且決策者也可能一點也不在乎自然鍵的「神聖不可侵犯」。有時候乙個列最開始是像是個很好的自然主鍵,但隨後有允許合法的重複項。此時偽主鍵便成了唯一的選擇。

在合適的時候也可以使用聯合主鍵,比如一條記錄可以通過多個列的組合完全定位。就像上面提到的contact表,那就通過那些列建立乙個聯合主鍵吧。

總結:我個人的見解就是能用**鍵就盡量用**鍵。除非**鍵真的非常多餘,就好似上面的組合鍵代替復合鍵的例子一樣。

資料庫主鍵ID管理方案

資料庫常常使用自增主鍵。通常會遇到這些問題 當我們在匯入舊資料時常常會發生主鍵重複衝突 資料庫主鍵沒有任何業務意義 常常會出現插入資料前需要獲取資料主鍵的情況,mysql下讓人頭大。生產過程中,常常用一張表以及函式來幫助維護業務表的主鍵。表用來存放業務表序列,函式用來處理並獲取業務表序列。當有業務資...

資料庫主鍵設計

主鍵的必要性 有些朋友可能不提倡資料庫表必須要主鍵,但在我的思考中,覺得每個表都應該具有主鍵,不管是單主鍵還是雙主鍵,主鍵的存在就代表著表結構的完整性,表的記錄必須得有唯一區分的字段,主鍵主要是用於其他表的外來鍵關聯,本記錄的修改與刪除,當我們沒有主鍵時,這些操作會變的非常麻煩。主鍵的無意義性 我強...

談資料庫主鍵選取策略

int和guid,究竟選誰?關於資料庫主鍵的選取策略,大家都是在int和guid兩者中徘徊。忘了那些喋喋不休的爭論吧!畢竟魚與熊掌,不可兼得。在這篇文章中,我們不再關注它們的優缺點,自覺先行做點功課哦!如小標題,如果真要選,我會選誰?肯定地說,我會選guid,又或者兩者都選上。後者情形下,使用gui...