Database-Design

如何為支持回复的私人消息系統建構表?

  • October 31, 2021

我正在用 PHP 編寫一個私人消息傳遞 Web 應用程序,該應用程序允許回复,這樣當您查看消息時,您還可以查看回复內容、回复內容以及回复內容一個回復等等等等。

我正在嘗試找到一個可以避免冗餘的正確數據庫結構,所以我想知道如何將單個消息連結到它正在回复的所有其他消息?

我想過基本上有一個名為 reply_id 的欄位,它將是一個序列化數組,其中包含要作為回复呈現的所有消息的 ID

有沒有人有關於如何有效地做到這一點的建議?我的想法是一個好的實踐嗎?

分層自引用數據

使用免費和開源數據庫PostgreSQL顯示的語法

您需要一個自引用表,它在數據庫中創建層次結構。這就是它的外觀。

CREATE TABLE messages (
 ts_entered  timestamp DEFAULT now(),
 reply_to    int       REFERENCES messages,
 id          int       PRIMARY KEY
                       GENERATED BY DEFAULT AS IDENTITY,
 content     text,
 CHECK (reply_to <> id)
);
CREATE INDEX ON messages (reply_to, id);

請注意,在非常表上引用一個 id:我們可以使用約束reply_id使其排除相同的 id 。您還可以編寫一個約束以確保小於這將阻止循環結構在數據庫中出現。id``CHECK``CHECK``reply_to``id

然後我們像這樣輸入測試數據。

INSERT INTO messages ( reply_to, id, content )
VALUES
 ( null, 1, 'SYN'),
 ( 1,    2, 'SYN-ACK'),
 ( 2,    3, 'ACK'),
 ( null, 4, 'We should give free advertising to PLAN EXPLORER'),
 ( 4,    5, 'Admins should disclose their affiliations with products'),
 ( 5,    6, 'BANNNN'),
 ( 4,    7, 'Plan Explorer only works on one database'),
 ( 7,    8, 'BANNNN'),
 ( 4,    9, 'Plan Explorer does not support Linux'),
 ( 9,   10, 'BANNNN'),
 ( 4,   11, 'Plan Explorer only does what decent databases already do'),
 ( 11,  12, 'BANNNN')
; 

現在為了查詢這個,我們需要一個RECURSIVE CTE.

WITH RECURSIVE t(reply_to, id, content, root, level)
AS (
 SELECT reply_to, id, content, ARRAY[id], 0
 FROM messages
 WHERE reply_to IS NULL
 UNION ALL
   SELECT messages.reply_to, messages.id, messages.content, root + ARRAY[messages.id], t.level+1
   FROM t
   JOIN messages
     ON (messages.reply_to = t.id)
)
SELECT * FROM t
ORDER BY root;

你完成了..

reply_to | id |                         content                          |   root    | level 
----------+----+----------------------------------------------------------+-----------+-------
         |  1 | SYN                                                      | {1}       |     0
       1 |  2 | SYN-ACK                                                  | {1,2}     |     1
       2 |  3 | ACK                                                      | {1,2,3}   |     2
         |  4 | We should give free advertising to PLAN EXPLORER         | {4}       |     0
       4 |  5 | Admins should disclose their affiliations with products  | {4,5}     |     1
       5 |  6 | BANNNN                                                   | {4,5,6}   |     2
       4 |  7 | Plan Explorer only works on one database                 | {4,7}     |     1
       7 |  8 | BANNNN                                                   | {4,7,8}   |     2
       4 |  9 | Plan Explorer does not support Linux                     | {4,9}     |     1
       9 | 10 | BANNNN                                                   | {4,9,10}  |     2
       4 | 11 | Plan Explorer only does what decent databases already do | {4,11}    |     1
      11 | 12 | BANNNN                                                   | {4,11,12} |     2
(12 rows)

我建議不要使用序列化數組,而是鼓勵您將功能建構到數據庫中,以便可以更輕鬆地擴展和管理它。

鑑於您正在考慮實現一個序列化數組,我假設消息可以是對零個或多個其他消息的回复。

在這種情況下,回复連結表將是一個很好的解決方案:

在此處輸入圖像描述

除了這是一種對數據庫更友好的設計之外,它還使得插入或刪除回复比在其他情況下要簡單得多。從這個解決方案編寫查詢也將比在序列化數組設計中容易得多。

例如,如果我想找到一條消息的所有回复,這很簡單:

SELECT ReplyingMessageID
FROM Reply r
WHERE ReplyTargetMessageID = <OurMessageID>

並且獲取具有特定文本的消息已回复的所有消息的文本也相對簡單:

SELECT m1.MessageInfo
FROM Message m1
INNER JOIN Reply r
   ON r.ReplyTargetMessageID = m1.MessageID
INNER JOIN Message m2
   ON m2.MessageID = r.ReplyingMessageID
   AND m2.MessageInfo = 'This is the text of the message that replied.'

從數據庫的角度來看,使用序列化數組獲取這些數據集中的任何一個都會有更大的問題。

引用自:https://dba.stackexchange.com/questions/97963