本文的目標就是要確認那些使用了主鍵,卻混淆了主鍵的本質而造成的一種反模式。
每個了解資料庫設計的人都知道,主鍵對於一張表來說是乙個很重要,甚至必需的部分。這確實是事實,主鍵是好的資料庫設計的一部分。主鍵是資料庫確保資料行在整張表唯一性的保障。它是定位到一條記錄並且確保不會重複儲存的邏輯機制。主鍵也同時可以被外來鍵引用來建立表與表之間的關係。
難點是選擇那一列作為主鍵。大多數表中的每個屬性值都有可能被很多行使用。例如姓名,電子郵件位址等等都不能保證不會重複。
在這樣的表中,需要引入乙個對於表的域模型無意義的新列來儲存乙個偽值。這一列被用作這張表的主鍵,從而通過它來確定表中的一條記錄,即便其他的列允許出現適當的重複項。這種型別的主鍵列我們通常稱其為偽主鍵或者**鍵。
大多數資料庫提供一種和當前處理事務無關的底層方案,來確保每次都能生成全域性唯一的乙個整數作為偽主鍵,即使客戶端此時正發起併發操作。
主鍵存在的作用:
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*這種查詢必須在查詢時指定列別名,否則其中的乙個id列會覆蓋掉另一列的id的值。from accout asa
join bug b on (b.toid = a.id)
同時有兩張表有相同的id列的情況下也不能夠使用using關鍵字。
比如:sql支援一種簡潔的表示式來表示兩張表聯結(using)。如果兩張表有同樣的列名,就可以用如下的表示式來重寫上面的需求。
select然而,如果所有的表都要求定義乙個叫做id的偽主鍵,那麼將不能使用這種簡寫方式。*from account join bug using(bug_id); --
乙個主鍵,乙個外來鍵。
4、使用組合鍵
一些開發人員覺得組合鍵太難使用,如果要比較兩個鍵值,必須比較其包含的所有列的值;乙個引用組合鍵的外來鍵,其本身也必須是乙個組合外來鍵。此外,使用組合鍵需要打更多的字。其實這是不對的。組合鍵的適當的時候是應該被使用的。
1、我覺得這張表不需要主鍵。
這麼說的人一定是誤解了「主鍵」和「偽主鍵」的含義,每張表都必須要有乙個主鍵,這個是毫無疑問的。實際上可能這個人需要的是乙個組合鍵,或者乙個更自然的列名來做主鍵。
2、我怎麼能在多對多的表中儲存重複的項?
在乙個對多對關係的交叉表中需要宣告乙個主鍵約束。或者至少需要有乙個針對那些被引用作為外來鍵的唯一約束。
使用偽主鍵,或者通過自動增長的整型的機制本身沒有什麼錯誤,但不是每張表都需要乙個偽主鍵,更沒有必要將每個偽主鍵都定義成id。
對於太長而不方便實現的自然鍵來說,偽主鍵是乙個很好的代替品。比如在乙個記錄檔案系統的所有檔案屬性的表中,檔案路徑是乙個很好的自然鍵,但對乙個字串列做索引的開銷會很大。
主鍵是約束而非資料型別。你可以定義任意列或任意多個的列作為主鍵。只要其資料型別支援索引。另外在此必須要補充的是,在sqlserver中,主鍵和聚集索引並沒必然的關係。sqlserver只是預設將聚集索引建在主鍵上,實際上你完全可以將聚集索引手動定義到非主鍵列。
1、為主鍵選擇更有意義的名稱
比如為product這張表的主鍵應該叫做product_id。
2、外來鍵應該盡可能地和所引用的列使用相同的名稱,這通常意味著:乙個主鍵的名稱應該在整個資料庫的設計中唯一;任意兩張表都不應該使用相同的名稱來定義主鍵,除非其中之一引用了另外乙個作為外來鍵。然而凡是都有例外,又是外來鍵的名稱需要和其所引用的主鍵區分開,從而使的它們之間的引用關係表現得更加清晰。
比如在一張外來鍵表中將外來鍵宣告為create_by(由誰建立)。
規則自然鍵**鍵
主鍵必須唯一的識別每一記錄
但與輸入和人為錯誤有關
系統自生成的資料是唯一的
乙個記錄的主鍵不能為空
只有資料可知時才能輸入記錄
當記錄生成時才被系統建立
當生成記錄時,主鍵的值必須存在
只有資料可知時才能輸入記錄
當記錄生成時才被系統建立當記錄生成時才被系統建立
主鍵必須保持穩定——你不能更改主鍵的域
自然鍵與一些商業規則和其他外部影響有關
**鍵對程式功能和資料保持中立
主鍵必須簡潔,不要包含過分的屬性
乙個自然鍵可以包含多個域
**鍵只能包含多個域
主鍵的值不能改變
自然鍵通常改變
**鍵通常不更改
如果你的表中包含一列能夠確保唯
一、非空以及能夠用來定位一條記錄,就別僅僅因為傳統而覺得有必要再加上乙個偽主鍵。
實踐證明,一張表中的每一列都在最初的設計之後遭遇改變是很正常的事情。資料庫的設計趨向於在整個專案的宣告週期中不斷地調整和優化,並且決策者也可能一點也不在乎自然鍵的「神聖不可侵犯」。有時候乙個列最開始是像是個很好的自然主鍵,但隨後有允許合法的重複項。此時偽主鍵便成了唯一的選擇。
在合適的時候也可以使用聯合主鍵,比如一條記錄可以通過多個列的組合完全定位。就像上面提到的contact表,那就通過那些列建立乙個聯合主鍵吧。
總結:我個人的見解就是能用**鍵就盡量用**鍵。除非**鍵真的非常多餘,就好似上面的組合鍵代替復合鍵的例子一樣。
資料庫主鍵ID管理方案
資料庫常常使用自增主鍵。通常會遇到這些問題 當我們在匯入舊資料時常常會發生主鍵重複衝突 資料庫主鍵沒有任何業務意義 常常會出現插入資料前需要獲取資料主鍵的情況,mysql下讓人頭大。生產過程中,常常用一張表以及函式來幫助維護業務表的主鍵。表用來存放業務表序列,函式用來處理並獲取業務表序列。當有業務資...
資料庫主鍵設計
主鍵的必要性 有些朋友可能不提倡資料庫表必須要主鍵,但在我的思考中,覺得每個表都應該具有主鍵,不管是單主鍵還是雙主鍵,主鍵的存在就代表著表結構的完整性,表的記錄必須得有唯一區分的字段,主鍵主要是用於其他表的外來鍵關聯,本記錄的修改與刪除,當我們沒有主鍵時,這些操作會變的非常麻煩。主鍵的無意義性 我強...
談資料庫主鍵選取策略
int和guid,究竟選誰?關於資料庫主鍵的選取策略,大家都是在int和guid兩者中徘徊。忘了那些喋喋不休的爭論吧!畢竟魚與熊掌,不可兼得。在這篇文章中,我們不再關注它們的優缺點,自覺先行做點功課哦!如小標題,如果真要選,我會選誰?肯定地說,我會選guid,又或者兩者都選上。後者情形下,使用gui...