为我的特定用例设计数据库的有效方法

Efficient Way To Design Database For My Specific Use Case

我正在建立一个网站,用户可以在其中查看从我的 gmail 帐户中提取的电子邮件。

用户可以阅读电子邮件、更改他们的标签并将其存档。每封电子邮件都有与之关联的元数据,用户可以根据元数据搜索电子邮件。此外,每个用户都与一个组织相关联。任何一个用户对电子邮件所做的更改(例如,如果电子邮件已存档,或者如果标签已更改)都会反映在整个组织中。

现在,我将所有电子邮件连同它们的元数据存储在一个 table 中。然而,问题是我现在数据库中有超过20,000封电子邮件,并且根据元数据搜索它们需要太多时间。

现在优化这一点的一种方法是,当用户运行搜索命令时,系统应该只搜索收件箱中未存档或删除的电子邮件。但问题是,一个组织可能存档了一封电子邮件,而另一个组织可能没有。所以我无法为收件箱和存档创建单独的 table。默认情况下,电子邮件也会在一段时间后自动存档(也可以禁用此选项),因此收件箱通常有大约 4000 封电子邮件,而存档有很多倍。

我的问题是为每个组织创建单独的收件箱和存档 table 并将所有新收到的电子邮件复制到 table 是否有意义?由于组织只能通过邀请加入,所以我预计总数不会超过 100。或者这会不会爆炸并在以后的代码中变得太难处理,有这么多 table。

我正在为此使用 PostgreSQL。

如果您的操作流程说“在添加新客户时创建 such-and-such 一个 table”,那么您的数据库设计存在严重问题。当您有超过 50 个客户时,由于 per-table 开销,速度会变慢。换句话说,当您开始在业务上取得成功时,您将开始在绩效上失败。不好。

您有一个 message 实体。毫无疑问,它包含消息的文本、主题、时间戳、发件人、收件人以及构成原始消息一部分的其他属性。每条消息都有一个唯一的(主键)message_id。但是实体不应包含 inboxarchive 等属性,因为这些属性与组织相关。

您需要一个 org 实体。每个组织都有一个唯一的org_id、一个'name和组织的其他属性。

那么你需要一个 org_message table。它的主键包含 org_idmessage_id。它将包含像 archivedread 这样的布尔属性,以及一个命名其当前 folder 的 VARCHAR 属性。所以,每个 org 的 window 到你的 message table 是由 org_messages.

组织的

如果您从一个名为 shipping 的组织开始,并且您想要查看它的所有消息,您可以使用这样的查询。

SELECT org.id, org.name,
       message.*,
       COALESCE(org_message.read, 0) unread,
       COALESCE(org_message.archived, 0) archived,
       COALESCE(org_message.folder, 'inbox') folder
  FROM org
  LEFT JOIN org_message ON org.org_id = org_message.org_id
  LEFT JOIN message ON message.message_id = org_message.message_id
 WHERE org.name = 'shipping';

LEFT JOIN 和 COALESCE 用于将每个组织的每条消息的默认设置设置为未读、未存档且位于 inbox 文件夹中。这样,在组织处理消息之前,您不必在 org_message 中为每个组织和每条消息创建一行。

如果您想为特定组织将消息标记为已读和存档,请使用 ON CONFLICT DO UPDATE

将一行插入 org_message
INSERT INTO org_message (org_id, message_id, read, archived, folder)
                 VALUES (?, ?, ?, ?, ?) ON CONFLICT DO UPDATE;

设置或更新消息的组织属性

如果您发现搜索这些 table 太慢,您将需要索引。那是另一个问题的主题。