2017-07-14 36 views
1

我大量使用引用在SQL佈局,並想知道,如果這是一個壞習慣。正如我在varchar(20)中聲明的一個參考文獻,PostgreSQL會使存儲使用率翻倍,或者只是使用隱藏的ID來鏈接這些值?PostgreSQL的存儲需要引用

一個例子:

create table if not exists distros(
    name varchar(20), 
    primary key(name) 
); 

create table if not exists releases(
    distro varchar(20) references distros(name), 
    name varchar(20), 
    primary key(distro, name) 
); 

create table if not exists targets(
    distro varchar(20) references distros(name), 
    release varchar(20) references releases(name), 
    name varchar(20), 
    primary key (distro, release, name) 
); 

是一次或三次存儲distro價值?

謝謝

+0

您的'目標'表應該有一個外鍵放入由'*目標'中的'distro'和'release'列組成的'releases'。 –

回答

1

我affraid,你的列distro不存儲一次或三次,但更多。 它在你的每張桌子上。但是,除此之外,您已將它作爲主鍵的一部分,從而使其成爲您將爲表定義的每個索引的一部分。

創建表這種方式。它將爲您節省大量空間,並且速度更快。

create table if not exists distros(
    id serial, 
    name varchar(20), 
    primary key(id) 
); 

create table if not exists releases(
    id serial, 
    distro_id int references distros(id), 
    name varchar(20), 
    primary key(id) 
); 

create table if not exists targets(
    id serial, 
    distro_id int references distros(id), 
    release_id int references releases(id), 
    name varchar(20), 
    primary key (id) 
); 
+0

在Postgres中,如果你不喜歡''id'列應該有一個串行數據類型不想填補你自己。這種結構對於所有用途來說不一定更快。例如,要僅從'targets'表中選擇數據,並在輸出中包含發行版名稱,則需要加入到'distros'表中,而如果使用自然鍵,則不需要連接。而且,給定的結構可以容納'targets'表中不存在於'releases'表中的發行版和發行版的組合 - 可能是數據完整性錯誤。 –

+0

@rd_nielsen我按照你的建議解決了id數據類型的問題。 OP使用外鍵,因此數據完整性得到執行。而且你有時候可能會更好地使用別的東西而不是id。但大多數情況下並非如此。 –

+0

非常感謝你,我會改變佈局 – pausiert

0

您的數據重複。使用外鍵constraint(又名「引用」)僅僅意味着如果列中不存在值,則不能在引用列中存在值。

tutorial是值得一讀。

+0

所以更好的方法是生成ID並創建一個將表連接在一起的視圖? – pausiert

+1

是的,只具有ID的是一個共同的設計 – JGH

+0

如果您當前的鍵不是整數大得多這使得特別感覺。如果它們不是(即:「字符(5)」),那就沒有必要。如果你有'varchar(20)',並且大多數情況下你使用超過3或者4個字符,那麼它是有意義的。 – joanolo

0

我不知道Postgres存儲佈局,但我認爲,每個記錄都應該完全存儲在一個所謂的數據頁中,以便在使用tablescans(不使用索引進行搜索)的情況下不需要額外的解除引用。也包括所有這些引用屬性。 此外,它將至少部分存儲在每個索引中,從哪裏引用的記錄將使用某種記錄ID找到,這取決於您使用的索引技術。正常的B(*)樹將以這種方式工作。

所以答案是至少三次,並在一類中用於搜索所引用的記錄,各項指標累積方式。