資料庫設計——評論回覆功能

Coder 發表於 2022-11-24
資料庫

1、概述

評論功能已經成為APP和網站開發中的必備功能。本文主要介紹評論功能的資料庫設計。

評論功能最主要的是發表評論和回覆評論(刪除功能在後臺)。評論功能的擴充功能體現有以下幾方面:
(1)單篇文章的評論數量和資訊展示;
(2)從時間維度,按照時間倒敘的方式展示動態的使用者評論資訊;
(3)不同欄目,不同模組,不同時間維度的評論排行展示;
(4)精華評論的單獨推薦和聚合展示;
(5)評論後直接分享到繫結的第三方平臺;
(6)點贊數、回覆數等維度的排行等。

評論的後臺管理:
(1)刪除;
(2)推薦;
(3)精華;
(4)遮蔽,敏感關鍵字的庫的完善、自動遮蔽或者替換功能。

本篇文章主要分析幾種客戶端評論資料表的設計。

2、資料表設計

2.1 一問一答模式

(1)需求分析

大部分APP採用簡單的評論設計即可,即是一問一答模式,比如微信朋友圈的評論功能的設計。如:

徐志勝:怎麼回事?
何廣智@徐志勝:你就是一條舔人的海狗!

這種設計簡單、直接,也滿足了使用者評論、回覆的基本要求,對於沒有大量使用者評論的APP需求足夠。

(2)資料庫設計

這種場景下一般評論較少,評論不活躍,可以不區分評論和回覆,統一看成評論。區別是,有些評論是直接評論主題,而有些是@其他使用者,使用一張表就可以達到效果,評論表設計如下:

表欄位欄位說明
id主鍵
topic_id主題id
topic_type主題型別
content評論內容
from_uid評論使用者id
to_uid評論目標使用者id

topic_type:為了能複用評論模組,我們引入這個欄位來區分主題的類別。

from_uid:表示評論人的id,透過該id我們可以檢索到評論人的相關資訊。

to_uid 是評論目標人的id,如果沒有目標人,則該欄位為空

出於效能的考慮,往往我們會冗餘評論人的相關資訊到評論表中,比如評論人的暱稱、頭像,目標使用者也是如此。 這樣一來我們就只用查詢單表就可以達到顯示的效果

有時,目標使用者有多個,那麼可以將to_uid欄位修改為to_uids,儲存時用分隔符來分割使用者id,而目標使用者的資訊再去查詢快取或者資料庫。也可以簡單的將多個目標使用者的資訊一起存成json格式,可以應付簡單的展現需求。

2.2 評論為主模式

(1)需求分析

如果以評論為主的顯示模式,類似於下面的CSDN的評論顯示模式:
資料庫設計——評論回覆功能
這裡將評論分為評論和回覆,所有評論均掛在評論下面,類似於樹狀結構。

(2)資料庫設計

在以評論為主的樹形顯示情況下,資料庫的設計十分靈活,可以使用單表,新增一個parent_id欄位來指向父評論,需要巢狀查詢。

同時也可以將評論拆分為評論表和回覆表,評論掛在各種主題下面,而回復掛在評論下面。

評論表設計如下:

表欄位欄位說明
id主鍵
topic_id主題id
topic_type主題型別
content評論內容
from_uid評論使用者id

回覆表設計:

表欄位欄位說明
id主鍵
comment_id評論id
reply_id回覆目標id
reply_type回覆型別
from_uid回覆使用者id
to_uid目標使用者id

由於我們拆分了評論和回覆,那麼評論表就不再需要目標使用者欄位了,因為評論均是使用者對主題的評論,評論表的設計更佳簡潔了。

回覆表新增了一個comment_id欄位來表示該回復掛在的根評論id,這樣設計也是出於效能方面的考慮,我們可以直接透過評論id一次性的找出該評論下的所有回覆,然後透過程式來編排回覆的顯示結構。 透過適當的冗餘來提高效能也是常用的最佳化手段之一。

reply_type:表示回覆的型別,因為回覆可以是針對評論的回覆(comment),也可以是針對回覆的回覆(reply), 透過這個欄位來區分兩種情景。

reply_id:表示回覆目標的id,如果reply_type是comment的話,那麼reply_id=commit_id,如果reply_type是reply的話,這表示這條回覆的父回覆。

2.3 網易新聞蓋樓模式

(1)需求分析

這種場景中評論和回覆是同級顯示的,回覆不在顯示結構上不用掛在一個評論下面。 雙表的設計在這裡就不太合適了,因為涉及到評論和回覆的混排,使用雙表則會導致查詢的邏輯過於複雜。 所以建議還是採用單表的設計,不區分評論和回覆會簡化應用層的邏輯。 我們統一都看成評論,而有些評論是可以引用其他評論的。

(2)資料庫設計

本人推薦採用閉包表的設計,例如:

comment表設計:

表欄位欄位說明
id主鍵
topic_id主題id
topic_type主題型別
content評論內容
from_uid評論使用者id

parent_child表:

表欄位欄位說明
parent_id父id
child_id子id

comment表儲存所有評論內容,而parent_children表則記錄評論表中各個評論的父子關係。

查詢時往往會按照時間排序,我們可以直接按id或者建立時間降序排列查詢comment表即可。 如果使用者想查詢一條評論的完整引用,則可以透過parent_children來找到對應的路徑。

閉包表在查詢時非常方便,但是插入的效能稍差,因為除了插入評論表以外,還需要把該條評論所有的父子關係插入到父子關係表中。 插入效能會隨著評論層級的加深而線性下降。

3、資料庫最佳化

如果你的系統每天都會擁有成千上萬條評論,那麼單表的設計肯定是不行,最佳化的方式有以下幾種思路。

(1)分庫分表。 分庫分表是最為常用也最有效的最佳化方式,建議按照主題來分庫分表。 這樣同一個主題下面的評論就會落到同一張表裡,避免了跨表查詢。

(2)適當的資料冗餘。 如果你需要顯示評論人的相關資訊,那麼在插入評論時就把這些資訊寫入評論表中,避免多次查詢。 實際上,如果是紀錄資料,都可以冗餘對應的資料資訊,因為它們的資料的實時行和一致性要求並不高。

(3)附加冪。資料只允許單項操作。 因為從冪性的要求來說,每個贊全都是一條記錄。 評論的贊數如果都從點贊表中統計得出,那麼效能開銷會十分巨大,而且點贊如此輕量級的一個操作一定會加劇點贊表的競爭操作。 所以建議直接在評論表中新增一個like_count的計數器,該欄位只增不減。客戶端,可以設定取消效果。

(4)熱門評論加快取。 類似於網易新聞的熱門評論,讀取頻度非常高,可以專門開介面做快取。