书签系统的数据库设计

5 schema erd normalization database-design

我正在创建一个书签系统,人们可以在其中保存他们的书签。每个用户都有自己的带有书签的个人页面。书签应至少有一个标签,最多五个。每个用户可以创建无限的书签/标签。

我创建了以下表格:

User
----
Id
Email


Bookmark
--------
Id
UserId
Title
Url


Tag
---
Id
UserId
Title
Description


TagBookmark
-----------
TagId
BookmarkId
Run Code Online (Sandbox Code Playgroud)

这是正常化了吗?或者我应该采取不同的做法?对于一百万个书签来说,这会表现良好吗?

我也不确定是否应该重用现有的书签/标签。

示例1:

User1 和 User2 都创建书签“ http://google.com ”。我应该将其保存为一个书签吗?或者为每个用户单独保存它们?

示例2:

User1 和 User2 都创建标签“search-engine”。我应该将其另存为一个标签吗?或者为每个用户单独保存它们?

如果我不在用户之间重复使用书签和标签,这些表可能会变得相当大。

Han*_*non 2

为了实现预期的大型用户群的最佳性能,我建议确保书签和标签不会出现不必要的重复。使用下面我建议的架构,http://google.com/将成为单个书签行。想要 Google 书签的用户将有一行UserBookmarksTags引用书签行和关联的标签行。

我倾向于将 UserID 从 Bookmarks 表中抽象出来,并使用交叉引用表来确定哪些用户拥有书签,以及他们为每个书签标记的内容。

使用 SQL Server,我会这样做:

USE tempdb;
GO
CREATE TABLE Users
(
    UserID INT NOT NULL 
        CONSTRAINT PK_Users
        PRIMARY KEY CLUSTERED
        IDENTITY(1,1)
    , UserName varchar(255)
);
CREATE TABLE Bookmarks
(
    BookmarkID INT NOT NULL
        CONSTRAINT PK_Bookmarks
        PRIMARY KEY CLUSTERED
        IDENTITY(1,1)
    , BookmarkName varchar(255)
    , BookmarkURL varchar(255)
);
CREATE TABLE Tags
(
    TagID INT NOT NULL
        CONSTRAINT PK_Tags
        PRIMARY KEY CLUSTERED
        IDENTITY(1,1)
    , TagName varchar(255)
);
Run Code Online (Sandbox Code Playgroud)

如果系统中的每个条目都需要书签和标签,则可以使用下表以获得最佳性能:

CREATE TABLE UsersBookmarksTags
(
    UserID INT NOT NULL
        CONSTRAINT FK_UsersBookmarksTags_UserID
        FOREIGN KEY REFERENCES Users(UserID)
    , TagID INT NOT NULL
        CONSTRAINT FK_UsersBookmarksTags_TagID
        FOREIGN KEY REFERENCES Tags(TagID)
    , BookmarkID INT NOT NULL
        CONSTRAINT FK_UsersBooksmarksTags_BookmarkID
        FOREIGN KEY REFERENCES Bookmarks(BookmarkID)
    , CONSTRAINT PK_UsersBookmarksTags
        PRIMARY KEY CLUSTERED 
        (UserID, TagID, BookmarkID)
);
Run Code Online (Sandbox Code Playgroud)

上述版本的表UsersBookmarksTags允许您快速返回与任何给定标签匹配的特定用户的书签列表,或该用户的所有书签。

或者,您可以创建允许标签和书签为空条目的交叉引用表,如下所示:

CREATE TABLE UsersBookmarksTags
(
    UsersTagsBookmarksID INT NOT NULL
        CONSTRAINT PK_UsersBookmarksTags
        PRIMARY KEY CLUSTERED
        IDENTITY(1,1)
    , UserID INT NOT NULL
        CONSTRAINT FK_UserBookmarks_UserID
        FOREIGN KEY REFERENCES Users(UserID)
    , TagID INT NULL
        CONSTRAINT FK_UserBookmarks_TagID
        FOREIGN KEY REFERENCES Tags(TagID)
    , BookmarkID INT NULL
        CONSTRAINT FK_UserBooksmarks_BookmarkID
        FOREIGN KEY REFERENCES Bookmarks(BookmarkID)
);
Run Code Online (Sandbox Code Playgroud)

这允许具有没有标签的书签的行,并且还允许将标签与没有书签的用户相关联。

如果需要知道用户添加的所有标签,而这些标签不一定有关联的书签,我会考虑为此目的添加另一个表,如下所示:

CREATE TABLE UserTags
(
    UserID INT NOT NULL
        CONSTRAINT FK_UserTags_UserID
        FOREIGN KEY REFERENCES Users(UserID)
    , TagID INT NOT NULL
        CONSTRAINT FK_UserTags_TagID
        FOREIGN KEY REFERENCES Tags(TagID)
    , CONSTRAINT PK_UserTags
        PRIMARY KEY CLUSTERED 
        (UserID, TagID)
);
Run Code Online (Sandbox Code Playgroud)