2008-10-01 157 views
44

我目前正在設計一個全新的數據庫。在學校裏,我們總是學會在每張桌子上放一個主鍵。主鍵與唯一約束?

我讀了很多文章/討論/新聞組的帖子,說最好是使用唯一約束(又名某個數據庫的唯一索引)而不是PK。

你的觀點是什麼?

回答

38

你能提供這些文章的參考嗎?

我看不出有什麼理由去改變嘗試過的和真正的方法。畢竟,主鍵是關係數據庫的基本設計特徵。

使用UNIQUE來達到相同的目的聽起來真的很討厭我。他們的理由是什麼?

編輯:我的注意力剛剛回到這個舊的答案。也許你讀到的關於PK和UNIQUE的討論涉及到人們爲了強制唯一性而做一些PK。對此的答案是,如果它是一個關鍵字,那麼將其設爲關鍵字,否則將其設爲唯一。

+1

你說,如果它是一個關鍵,使它成爲一個關鍵,如果它是唯一的,使其獨特。但是,真的,什麼使鑰匙成爲鑰匙而不是唯一的鑰匙?你對*鍵的定義是什麼? – Pacerier 2013-11-22 21:38:04

+0

@Prier假設我們有一個學生信息數據庫。在這個數據庫中,學生用主鍵StudentNumber標識。 在學生表中,我們保留諸如SSN/SIN或其他區域等價物。作爲密鑰錯誤檢查的一部分,我們希望這個字段是唯一的。但這不是關鍵領域。 (儘管可能,假設StuID和SSN之間的1:1對應關係) 房間分配也可以是唯一的,但不是關鍵。 (雖然我更傾向於將學生分配到一個房間,而不是一個房間給學生) – 2013-11-28 13:48:21

+0

在你的例子中,爲什麼不把SSN/SIN作爲鑰匙? – Pacerier 2013-11-30 03:52:44

9

這將是非常罕見的非規範化,會讓你想要一個沒有主鍵的表。主鍵自動地具有唯一的約束,就像PK一樣。

當您想要保證主鍵的附加列中的唯一性時,將使用唯一的約束。

總是有一個PK的規則是一個很好的規則。

http://msdn.microsoft.com/en-us/library/ms191166.aspx

3

主鍵應該在那裏你會被從該表建立關係,以將引用這個值其它表的情況下使用。但是,根據表格的性質以及您正在考慮應用唯一約束的數據,您可能可以將該特定字段用作自然主鍵,而不必建立替代鍵。當然,代理與自然鍵是一個完整的其他討論。 :)

如果此表和其他表之間沒有建立關係,則可以使用唯一鍵。例如,一個包含有效電子郵件地址列表的表格,它將在插入新用戶記錄或其他類型之前進行比較。或者,如果表中具有主鍵但必須是絕對唯一的值,則可以使用唯一鍵。例如,如果您有一個擁有用戶名的用戶表。您不希望將用戶名稱用作主鍵,但它也必須是唯一的,以便將其用於登錄目的。

1

問題是主鍵可以是一個或多個列,它唯一地標識一個表的單個記錄,其中唯一約束只是一個字段上的約束,它只允許任何給定數據元素的單個實例一張桌子。個人而言,我使用GUID或自動遞增BIGINTS(用於SQL SERVER的身份插入)作爲我的表中用於交叉引用的唯一鍵。然後我會使用其他數據來允許用戶選擇特定的記錄。

例如,我將列出僱員名單,並在每個記錄後附加GUID,但是當用戶選擇一名僱員時,他們會根據以下字段選擇他們:姓氏+名字+員工號碼。

在這種情況下,我的主鍵是LastName + FirstName + EmployeeNumber,而唯一鍵是關聯的GUID。

10

主鍵只是一個候選關鍵字(唯一約束),用於特殊處理(自動創建索引等)。

我認爲那些反對他們的人認爲沒有理由對待一個關鍵字而不是另一個。這就是我的立場。

[編輯]顯然我不能評論,即使我自己的答案沒有50分。

@chris:我認爲沒有任何傷害。 「主鍵」實際上只是句法糖。我一直使用它們,但我當然不認爲它們是必需的。需要獨特的密鑰,是的,但不一定是主密鑰。

0

如果您計劃使用LINQ-to-SQL,如果您打算執行更新,那麼您的表將需要主鍵,如果您打算在斷開連接的環境中工作(如傳遞對象),則需要timestamp列通過WCF服務應用程序)。

如果你喜歡.NET,PK和FK是你的朋友。

46

主鍵實際上只是一個candidate key,它不允許NULL。因此,用SQL語言來說 - 它與其他任何唯一密鑰沒有區別。

但是,對於我們的非理論型關係數據庫管理系統,您應該有一個主鍵 - 我從來沒有聽說過其他方面的爭論。如果該主鍵是surrogate key,那麼您應該natural key(s)有唯一的限制。

重要的一點是你應該對全部這個候選人(不管是自然的還是代理的)密鑰有獨特的限制。然後你應該選擇一個Foreign Key中最容易引用的主鍵*。您還應該有一個clustered index *。這可能是你的主鍵,或者一個自然鍵 - 但它不是必需的。您應該根據表的查詢使用情況選擇聚集索引。如果有疑問,主鍵不是不好的首選。

  • 雖然它在技術上只需要參考的唯一鍵的外鍵關係,它是公認的標準做法,以大大青睞的主鍵。事實上,如果某些RDBMS只允許主鍵引用,我不會感到驚訝。

  • 編輯:有人指出,Oracle的「聚集表」和「聚集索引」的術語不同於Sql Server。相當於我在Oracle-ese中所說的是Index Ordered Table,它被推薦用於OLTP表 - 我認爲這將是SO問題的主要焦點。我假設您是否對大型OLAP數據倉庫負責,您應該已經對數據庫設計和優化有自己的看法。

3

除非該表是一個臨時表,而你在這工作階段的數據,你總是希望把上表的主鍵和這裏的原因:

1 - 唯一約束可以讓空值,但主鍵從不允許空值。如果使用具有空值的列對聯接運行查詢,則會從結果數據集中刪除這些行,因爲null不等於null。這就是即使大公司也會犯會計錯誤,並且必須重申他們的利潤。他們的查詢沒有顯示應包含在總數中的某些行,因爲其唯一索引的某些列中存在空值。應該使用主鍵。

2 - 唯一索引將自動放置在主鍵上,因此您不必創建一個索引。

3 - 大多數數據庫引擎會自動在主鍵上放置聚簇索引,從而使查詢更快,因爲行連續存儲在數據塊中。 (如果這樣可以加快查詢的速度,則可以將聚集索引放置在不同的索引上)。如果表沒有聚集索引,那麼行將不會連續存儲在數據塊中,從而使查詢由於讀/寫磁頭必須遍歷整個磁盤來拾取數據,因此速度較慢。

4 - 很多前端開發環境需要主鍵才能更新表或進行刪除。

2

我們需要在這裏區分邏輯結構和物理結構,理論和實踐之間也是類似的。

首先:從理論的角度來看,如果你沒有主鍵,你沒有一張表。就這麼簡單。所以,你的問題不是你的表是否應該有一個主鍵(當然它應該),而是你如何在你的RDBMS中標記它。

在物理層面上,大多數RDBMS實現主鍵約束作爲唯一索引。如果您選擇的RDBMS是其中之一,那麼在將列指定爲主鍵和簡單地在該列上設置唯一約束之間可能沒有太大的實際區別。但是:其中一個選項可以捕捉您的意圖,而另一個則不會。所以,這個決定是不容易的。

此外,如果主鍵已正確標記(例如圖表和半自動外鍵約束支持),則某些RDBMS可提供其他功能。

任何告訴你使用唯一約束而不是主鍵的人都應該提供一個非常糟糕的理由。

1

帖子說這是更好地使用唯一約束(對於某些分貝又名唯一索引),而不是PK

我想,這裏的唯一的一點是相同的舊討論「自然VS代理鍵」 ,因爲獨特的索引和PK是同一回事。

翻譯:

帖子說這是更好地使用自然鍵而不是替代鍵

5

你應該總是主鍵。

但是我懷疑你的問題只是措辭有點誤導,你實際上是要問,如果主鍵應始終是一個自動生成的數字(也稱爲代理鍵),或一些獨特的字段是實際有意義的數據(也被稱爲自然鑰匙),就像人們的SSN,書籍的ISBN等等。

這個問題是一個古老的DB領域的宗教戰爭。

我的看法是,如果自然鍵確實是唯一的並且永遠不會改變,那麼它更可取。但是,您應該小心,即使在某些情況下,SSN等人可能會發生變化,但表面上看起來很穩定。

0

我提交您可能需要兩者。主鍵本質上需要是唯一的,不能爲空。它們通常是代理鍵,因爲整數創建比字符文件更快的連接,尤其是多字段字符連接。但是,由於這些通常是自動生成的,因此它們不保證數據記錄的唯一性,不包括id本身。如果你的表有一個應該是唯一的自然鍵,你應該有一個唯一的索引來防止重複數據的輸入。這是基本的數據完整性要求。

編輯補充:這也是一個現實的問題是現實世界的數據往往不具有真正保證了標準化的表結構的獨特性,特別是在數據庫爲以人爲本的自然鍵。姓名,甚至是姓名,地址和電話號碼(認爲父子在同一醫療實踐中)並不一定是唯一的。

1

我通常同時使用PK和UNIQUE KEY。因爲即使你沒有在模式中表示PK,也會在內部爲你生成一個。這是真的都對SQL Server 2005和MySQL 5

但我並不在我的sql語句使用PK列。這是爲了管理目的,如刪除一些錯誤的行,找到PK值之間的差距,如果它設置爲自動增量。而且,將PK作爲數字是有意義的,而不是一組列或字符數組。

1

我已經寫了很多關於這個問題:如果你看過我的任何明確的是,我可能特指噴氣又稱MS訪問。

在射流,這些表被物理下令使用非保持聚集索引PRIMARY KEY(被集羣上緊湊)。如果表沒有PK但是在NOT NULL列上使用UNIQUE約束定義候選鍵,那麼引擎將爲聚簇索引選擇一個(如果您的表沒有聚簇索引,那麼它被稱爲堆,可以說根本不是表!)引擎如何挑選候選鍵?它可以選擇一個包含空列的列嗎?我真的不知道。重點是在Jet中,爲引擎指定聚集索引的唯一明確方式是使用PRIMARY KEY。 Jet在PK中當然還有其他用途,例如如果從SQL DDL中的FOREIGN KEY聲明中省略了鍵,那麼它將用作鍵,但又是爲什麼不是顯式的。

與Jet的麻煩是誰創建表大多數人不知道的或不關心聚集索引。實際上,大多數用戶(我保證)在每個表上放置一個自動增量列,並且只在該列上定義PRIMARY KEY,而未對自然鍵和候選鍵設置任何唯一約束(自動增量列實際上是否可以被視爲一個關鍵沒有暴露給最終用戶本身是另一個討論)。我不會在這裏詳細討論聚集索引,但足以說IMO是唯一的自動增量列很少成爲理想的選擇。

不管你的SQL引擎,PRIMARY KEY的選擇是任意的,發動機比。通常發動機會對PK有特殊的意義,因此你應該知道它是什麼,並將它用於你的優勢。我鼓勵人們使用NOT NULL UNIQUE約束,希望他們能夠更好地考慮所有候選鍵,特別是當他們選擇使用'自動編號'列(在數據模型中應該沒有意義)時。但是我寧願選擇一個考慮得很好的密鑰,並使用PRIMARY KEY而不是放在自習增量欄中。

是否所有表都有PK?我說是的,因爲這樣做意味着至少你錯過了引擎提供PK的輕微優勢,最壞的情況是你沒有數據完整性。

BTW克里斯OC使得一個好點約在這裏無法通過簡單的PRIMARY KEY約束(SQL關鍵字用大寫)來實現的時態表,這需要測序主鍵(小寫)。

0

我在想我的這個問題。如果你使用獨特的,你會傷害2. NF。據此,每個非pk屬性必須取決於PK。這個唯一約束中的這對屬性將被視爲PK的一部分。

對不起回覆這款7年後的今天,但沒有要開始新的討論。

1

PRIMARY KEY

1.空 它不允許Null值。因此,我們參考PRIMARY KEY = UNIQUE KEY + NOT NULL CONSTRAINT。 2. INDEX 默認情況下,它增加了一個聚集索引。 3. LIMIT 甲表只能有一個主鍵列[s]的。

UNIQUE KEY

1.空 允許空值。但只有一個空值。 2. INDEX 默認情況下,它增加了一個獨特的非聚集索引。 3. LIMIT 一個表可以具有多於一個的唯一鍵列[s]的。