Messenger 資料庫(第 1 部分):設計基礎框架

如何使用從頭開始設計信使資料庫的範例將業務需求轉換為特定的資料結構。

Messenger 資料庫(第 1 部分):設計基礎框架
我們的基地不會那麼大和分散, 喜歡 VKontakteBadoo上,但“原來如此”,但它很好——功能齊全、速度快、 適合一台伺服器 PostgreSQL - 例如,您可以在側面的某個地方部署該服務的單獨實例。

因此,我們不會涉及分片、複製和地理分散式系統的問題,而是專注於資料庫內部的電路解決方案。

第 1 步:一些業務細節

我們不會抽像地設計訊息傳遞,而是將其整合到環境中 企業社交網絡。也就是說,我們的員工不只是“通信”,而是在解決某些業務問題的背景下相互溝通。

企業的任務是什麼?...讓我們來看看開發部主管瓦西里的例子。

  • “尼古拉,為了完成這項任務,我們今天需要一個補丁!”
    這意味著通信可以在某些背景下進行 該文件.
  • “Kolya,你今晚要去Dota嗎?”
    也就是說,即使是一對對話者也可以同時進行交流 關於各種主題.
  • “彼得,尼古拉,在附件中查找新伺服器的價目表。”
    所以,一則訊息可以有 幾個收件人。在這種情況下,訊息可能包含 附加的文件.
  • “謝苗,你也看看。”
    並且應該有機會進行現有的通信 邀請新成員.

現在讓我們詳細討論一下這個「明顯」需求清單。

在不了解問題的應用細節及其限制的情況下,設計 有效的 資料庫模式來解決它幾乎是不可能的。

第 2 步:最小邏輯電路

到目前為止,一切都與電子郵件通訊(一種傳統的商業工具)非常相似。是的,“從演算法上來說”,許多業務問題彼此相似,因此解決這些問題的工具在結構上也相似。

讓我們修復已經獲得的實體關係邏輯圖。為了讓我們的模型更容易理解,我們將使用最原始的顯示選項 急診室模型 沒有 UML 或 IDEF 符號的複雜性:

Messenger 資料庫(第 1 部分):設計基礎框架

在我們的範例中,文件的人、文件和二進位「主體」是獨立存在的「外部」實體,無需我們的服務。因此,我們將來會簡單地將它們視為 UUID「某處」的一些連結。

圖表盡可能簡單 - 您將向其展示的大多數人都不是閱讀 UML/IDEF 的專家。但一定要畫好。

第 3 步:繪製表結構草圖

關於表名和欄位名欄位和表格的“俄語”名稱可以不同地對待,但這是一個品味問題。 因為 在張量這裡 沒有外國開發者,而 PostgreSQL 允許我們甚至用象形文字來命名,如果他們 用引號引起來,那麼我們更願意明確、清楚地命名對象,這樣就不會出現差異。
由於很多人同時給我們寫訊息,有些人甚至可能這樣做 離線,那麼最簡單的選擇就是 使用 UUID 作為識別符 不僅適用於外部實體,也適用於我們服務內的所有物件。而且,它們甚至可以在客戶端產生——這將幫助我們支援在資料庫暫時不可用時發送訊息,並且發生衝突的可能性極低。

我們資料庫中的草稿表結構如下所示:
表 : RU

CREATE TABLE "Тема"(
  "Тема"
    uuid
      PRIMARY KEY
, "Документ"
    uuid
, "Название"
    text
);

CREATE TABLE "Сообщение"(
  "Сообщение"
    uuid
      PRIMARY KEY
, "Тема"
    uuid
, "Автор"
    uuid
, "ДатаВремя"
    timestamp
, "Текст"
    text
);

CREATE TABLE "Адресат"(
  "Сообщение"
    uuid
, "Персона"
    uuid
, PRIMARY KEY("Сообщение", "Персона")
);

CREATE TABLE "Файл"(
  "Файл"
    uuid
      PRIMARY KEY
, "Сообщение"
    uuid
, "BLOB"
    uuid
, "Имя"
    text
);

表:EN

CREATE TABLE theme(
  theme
    uuid
      PRIMARY KEY
, document
    uuid
, title
    text
);

CREATE TABLE message(
  message
    uuid
      PRIMARY KEY
, theme
    uuid
, author
    uuid
, dt
    timestamp
, body
    text
);

CREATE TABLE message_addressee(
  message
    uuid
, person
    uuid
, PRIMARY KEY(message, person)
);

CREATE TABLE message_file(
  file
    uuid
      PRIMARY KEY
, message
    uuid
, content
    uuid
, filename
    text
);

描述格式時最簡單的就是開始「展開」連結圖 來自未引用的表 自己對任何人都沒有。

第四步:找出非顯而易見的需求

就是這樣,我們設計了一個資料庫,您可以在其中完美地編寫和 不知何故 閱讀。

讓我們站在服務使用者的立場上思考—我們想用它做什麼?

  • 最後留言
    按時間順序排列 基於各種標準的「我的」訊息的註冊表。我是收件人之一,我是作者,他們寫信給我但我沒有回复,他們沒有回复我,......
  • 通信參加者
    誰參與了這場漫長的聊天?

我們的結構使我們能夠「總體上」解決這兩個問題,但速度不會很快。問題是在第一個任務中進行排序 無法建立索引,適合每個參與者(並且您必須提取所有記錄),並解決您需要的第二個 提取所有訊息 關於這個話題。

非預期的使用者任務可能會加粗 交叉生產力.

第 5 步:智慧反規範化

我們的兩個問題都將透過附加表格來解決,我們將在其中 重複部分數據,有必要在它們上形成適合我們任務的索引。
Messenger 資料庫(第 1 部分):設計基礎框架

表 : RU

CREATE TABLE "РеестрСообщений"(
  "Владелец"
    uuid
, "ТипРеестра"
    smallint
, "ДатаВремя"
    timestamp
, "Сообщение"
    uuid
, PRIMARY KEY("Владелец", "ТипРеестра", "Сообщение")
);
CREATE INDEX ON "РеестрСообщений"("Владелец", "ТипРеестра", "ДатаВремя" DESC);

CREATE TABLE "УчастникТемы"(
  "Тема"
    uuid
, "Персона"
    uuid
, PRIMARY KEY("Тема", "Персона")
);

表:EN

CREATE TABLE message_registry(
  owner
    uuid
, registry
    smallint
, dt
    timestamp
, message
    uuid
, PRIMARY KEY(owner, registry, message)
);
CREATE INDEX ON message_registry(owner, registry, dt DESC);

CREATE TABLE theme_participant(
  theme
    uuid
, person
    uuid
, PRIMARY KEY(theme, person)
);

這裡我們應用了建立輔助表時所使用的兩種典型方法:

  • 乘以記錄
    使用初始訊息記錄,我們在不同類型的暫存器中為不同的所有者(發送者和接收者)建立多個後續記錄。但現在每個暫存器都落在索引上 - 畢竟,在典型情況下,我們只想看到第一頁。
  • 獨特記錄
    每次在特定主題內發送訊息時,檢查此類條目是否已存在就足夠了。如果沒有,請將其添加到我們的“詞典”中。

在文章的下一部分我們將討論 分區的實現 進入我們資料庫的結構。

來源: www.habr.com

添加評論