2016-08-02 29 views
0

我正在爲我的Web構建數據進行建模。我使用Postgresql數據庫。建模SQL中的Post和Flag關係

在應用程序中有像SO帖子這樣的帖子,還有帖子的標誌作爲Github標誌或標記,無論正確的術語是什麼。一個帖子一次只能有一個標誌。有很多職位不斷增加,但是有四五個職位,他們不會增加。

第一種方法,歸一化;我用三張表格模擬了我的這部分數據;兩個用於相應的實體帖子和標誌,另一個用於關係爲post_flag。任何實體表中沒有提及其他實體表中的關係。所有的關係都被記錄在關係表post_flag中,並且這僅僅是用於帖子和標誌的id的id對。在這種情況下

表的結構將是:

CREATE TABLE posts 
(
    id bigserial PRIMARY KEY, 
    created_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP, 
    title character varying(100), 
    text text, 
    score integer DEFAULT 0, 
    author_id integer NOT NULL REFERENCES users (id), 
    product_id integer NOT NULL REFERENCES products (id), 
); 

CREATE TABLE flags 
(
    id bigserial PRIMARY KEY, 
    created_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP, 
    flag character varying(30) NOT NULL -- planned, in progress, fixed 
); 

CREATE TABLE post_flag 
(
    created_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP, 
    post_id integer NOT NULL REFERENCES posts (id), 
    flag_id integer NOT NULL REFERENCES flags (id) 
); 

要獲得標記的職位爲固定我必須使用:

-- homepage posts- fixed posts tab 
SELECT 
    p.*, 
    f.flag 
FROM posts p 

JOIN post_flag p_f 
ON p.id = p_f.post_id 
JOIN flags f 
ON p_f.flag_id = f.id 

WHERE f.flag = 'fixed' 
ORDER BY p_f.created_at DESC 

第二條本辦法;我有兩個表格文章和標誌。表格帖子有一個flag_id列,它引用flags表中的一個標誌。

CREATE TABLE posts 
    (
     id bigserial PRIMARY KEY, 
     created_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP, 
     title character varying(100), 
     text text, 
     score integer DEFAULT 0, 
     author_id integer NOT NULL REFERENCES users (id), 
     product_id integer NOT NULL REFERENCES products (id), 
     flag_id integer DEFAULT NULL REFERENCES flags (id) 
    ); 

    CREATE TABLE flags 
    (
     id bigserial PRIMARY KEY, 
     created_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP, 
     flag character varying(30) NOT NULL -- one of planned, in progress, fixed 
    ); 

對於相同的數據;

-- homepage posts- fixed posts tab 
SELECT 
    p.*, 
    f.flag 
FROM posts p 

JOIN flags f 
ON p.flag_id = f.id 

WHERE f.flag = 'fixed' 
ORDER BY p.created_at DESC 

第三種方法規格化;我只有一個表格文章。職位表有一個標誌列來存儲分配給職位的標誌。

CREATE TABLE posts 
     (
      id bigserial PRIMARY KEY, 
      created_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP, 
      title character varying(100), 
      text text, 
      score integer DEFAULT 0, 
      author_id integer NOT NULL REFERENCES users (id), 
      product_id integer NOT NULL REFERENCES products (id), 
      flag character varying(30) 
     ); 

在這裏,我只會有相同的數據;

-- homepage posts- fixed posts tab 
SELECT 
    p.*, 
FROM posts p 

WHERE p.flag = 'fixed' 
ORDER BY p.created_at DESC 

我不知道如果第一種方法在像Postgresql這樣的RDBMS中的數據規範化方面是過度殺傷性的嗎?對於後評論關係,第一種方法會很棒,而且我的確使用它。但是我有一些很少的數量數據用作徽章,標誌,標籤等帖子的元數據。正如你所看到的事實上是最正常的形式,第一種方法,我已經使用一些product_id等使用一個較少的JOIN,但另一個表作爲不同的關係,而不是標誌。所以,我的方法適合我的第二種方法。我應該使用更加非規範化的方法,第三種方法是在其中添加張貼表和標誌欄?在性能,擴展和可維護性方面有哪些更好的方法?

+0

它可能只是我,但看到你的不同表結構會比看到你用來對付它們的查詢在評估規範化程度和效果時更有益。 – alzee

+2

添加了數據結構。 –

回答

1

使用第二種方法。

第一個是多到多的數據結構和你說

一個帖子可以在同一時間只能有一個標誌。

因此,您必須將業務邏輯構建到前端或設置複雜的規則來檢查帖子永遠不會有多個標誌。

第三種方法會導致數據混亂,除非您執行檢查或規則以確保標記不拼寫或添加新標記。

第二種方法提供了擴展和可維護性;它也是自我記錄。擔心性能的時候它實際上變成了的問題,而不是之前。

就我個人而言,我會在postsNULL中設置flag_id字段,該字段允許您對沒有標記的帖子建模。

融合兩種方法

假設你的標誌名是唯一的,你可以使用該標誌的名稱作爲一種天然的關鍵。然後,您的表結構將

CREATE TABLE posts 
(
    id bigserial PRIMARY KEY, 
    ... other fields 
    flag character varying(30) REFERENCES flags (flag) 
); 

CREATE TABLE flags 
(
    flag character varying(30) NOT NULL PRIMARY KEY, 
    created_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP 
); 

然後你得到的能夠不必JOINflags表,同時具有標誌名稱由表引用檢查寫標誌查詢,而不利益。

+0

如果我在post_flag表中具有post_id唯一性,那麼對於「混合兩種方法」部分之前的部分,您的答案仍然是相同的,因此對該職位的標記進行更新並僅在此處進行,而不會爲帖子插入新行。其實第一個似乎有改變能力的歷史,如果我有另一個id列作爲PK,這使得它成爲多對多。如果一個帖子只需要一個標誌,並且歷史記錄也可以用WHERE子句選擇最新的時間標誌。 –

+0

如果我正確理解你的評論,你可以使'post_id'成爲唯一性的主鍵。那麼,是的,更新標誌只會改變'post_flag'表。但這聽起來像是過早的性能優化。您是否遇到了快速更新Poset標誌的問題? (我在編輯你的文章之前寫了這條評論) – Tony

+0

使用多對多的方法會給你一個帖子標誌的歷史記錄,這很有用。你需要它嗎?如果是這樣,那麼'post_flag'行的創建日期可以自動設置,然後用於獲取當前標誌。 – Tony