2011-08-24 53 views
6

我知道這是超基本的,但這是一個我一直持有的假設,並且想要驗證它是否正確(通常,具體針對各種實現的詳細信息)關於如何將外鍵數據存儲在SQL中的問題

比方說,我有一個表格,其中有一個文本列「水果」。在該專欄中,只有四個值中的一個出現:梨,蘋果,香蕉和草莓。我有一百萬行。

而不是每個重複數據(平均)四分之一百萬次,如果我將它提取到另一個具有水果列和只有這四行的表中,然後將原始列作爲外鍵,是否它節省空間?

我假設四個水果名稱只存儲一次,而且現在有數百萬行有指針或索引或者對第二個表的某種引用。

如果我的行值比短的水果名稱長,我認爲節省/優化更大。

回答

4

外鍵關係兩邊的字段的數據類型必須相同。

如果父表的關鍵字段是(比如說)varchar(20),那麼從屬表中的外鍵字段也必須是varchar(20)。這意味着,是的,你必須在每張表中重複X行「Apple」,「Pear」和「Banana」,這些表中有一個外鍵指向水果桌。

通常,使用數字字段作爲鍵(int,bigint)會更有效,因爲可以使用很少的CPU指令進行比較(通常可以直接進行一個cpu指令比較)。另一方面,字符串需要循環和相對昂貴的設置。所以是的,你最好將水果名稱存儲在某個表的某個表中,並將其相關的數字ID字段用作外鍵。

當然,您應該對兩個設置進行基準測試。這些只是一般的經驗法則,並且您的具體要求/設置實際上可以使用字符串作爲密鑰版本更快地工作。

+0

想象一個引用類型變量3GL,如C#.NET:它的值在內存中的一個位置退出,但可以有許多引用變量,它們只是指向該位置的整數(或其他)指針。同樣的原則可以應用於DBMS:邏輯上,FK中的兩個表都將水果作爲文本存儲,但在封面之下,文本只存儲一次,每個表物理地僅存儲一個指向相同值的整數(或其他)指針。 mySQL會這樣做嗎?我認爲這就是提問者所掌握的。 – onedaywhen

+1

我不會將mysql的數據存儲實踐與編程語言進行比較。只存儲一個副本是有意義的,但外鍵不是引用。他們只是一個像其他任何其他字段一樣的字段,其中包含的數據與另一個表中的等效字段/數據相匹配。畢竟,在大桌子上放置外鍵幾乎是瞬間的。如果它是一個參考,那麼現在參考消失後,DBMS將不得不復制真實數據。 –

5

這是正確的。

你應該有

table fruits 
id name 
1 Pear 
2 Apple 
3 Banana 
4 Strawberry 

其中ID是主鍵。 在你的第二張表中,你將只使用這張表的ID。這將爲您節省物理空間,並使您的選擇報表工作得更快。
此外,這種結構將使你很容易添加新的水果。

2

而不是重複的數據(平均)的四分之一萬次 每次,如果我將其解壓縮到具有一個水果塔和 只是那些四排,然後進行原始列外一個又一個表鑰匙, 它可以節省空間嗎?

如果「Fruit」是「lookup」表的主鍵,那麼它也必須是「large」表中的FOREIGN KEY。

但是,如果您在「lookup」表中創建一個小型代理PRIMARY KEY(例如整數「id」)並將其用作「large」表中的FOREIGN KEY,則可節省空間。

1

起初是的,它會節省空間,因爲int - 4個字節,TINYINT - 1個字節。其次,用TYPE INT搜索這個字段會比VARCHAR更快。除此之外,如果您的數據將來未更改,則可以使用ENUM。有了枚舉,你可以得到比輔助表更快的結果,你將避免額外的連接。

2

規範化不僅僅是關於空間,它通常是關於數據行爲的冗餘和建模,也是關於只更新一行以進行更改 - 並且通過僅更新最少量的數據來減少鎖的範圍。

0

我明白你不是真的是想用外鍵。 Aaah,Marc B剛剛公佈了FKs的含義。 但是使用第二個表作爲外部「名稱提供者」將確保節省空間。你需要在fruit.fruit_id上有一個額外的索引。這將是相當小,這將是NUMERIC。比char或varchar上的索引更快。

1

不幸的是,你認爲這是錯誤的:值爲每個引用表重複物理存儲。一些SQL產品確實只存儲了一次值,但大部分都不存在,特別是基於磁盤上連續存儲的更受歡迎的值。

這就是最終用戶覺得需要使用整數'代理鍵'來實現自己的要點的原因。系統替代品將是優選的,例如,對用戶來說是不可見的,就像系統維護一個索引的'值'一樣,用戶不能直接操作它們。滾動你自己的問題是他們成爲邏輯模型的一部分。

相關問題