为我的特定用例设计数据库的有效方法
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
。但是实体不应包含 inbox
和 archive
等属性,因为这些属性与组织相关。
您需要一个 org
实体。每个组织都有一个唯一的org_id
、一个'name
和组织的其他属性。
那么你需要一个 org_message
table。它的主键包含 org_id
和 message_id
。它将包含像 archived
和 read
这样的布尔属性,以及一个命名其当前 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 太慢,您将需要索引。那是另一个问题的主题。
我正在建立一个网站,用户可以在其中查看从我的 gmail 帐户中提取的电子邮件。
用户可以阅读电子邮件、更改他们的标签并将其存档。每封电子邮件都有与之关联的元数据,用户可以根据元数据搜索电子邮件。此外,每个用户都与一个组织相关联。任何一个用户对电子邮件所做的更改(例如,如果电子邮件已存档,或者如果标签已更改)都会反映在整个组织中。
现在,我将所有电子邮件连同它们的元数据存储在一个 table 中。然而,问题是我现在数据库中有超过20,000封电子邮件,并且根据元数据搜索它们需要太多时间。
现在优化这一点的一种方法是,当用户运行搜索命令时,系统应该只搜索收件箱中未存档或删除的电子邮件。但问题是,一个组织可能存档了一封电子邮件,而另一个组织可能没有。所以我无法为收件箱和存档创建单独的 table。默认情况下,电子邮件也会在一段时间后自动存档(也可以禁用此选项),因此收件箱通常有大约 4000 封电子邮件,而存档有很多倍。
我的问题是为每个组织创建单独的收件箱和存档 table 并将所有新收到的电子邮件复制到 table 是否有意义?由于组织只能通过邀请加入,所以我预计总数不会超过 100。或者这会不会爆炸并在以后的代码中变得太难处理,有这么多 table。
我正在为此使用 PostgreSQL。
如果您的操作流程说“在添加新客户时创建 such-and-such 一个 table”,那么您的数据库设计存在严重问题。当您有超过 50 个客户时,由于 per-table 开销,速度会变慢。换句话说,当您开始在业务上取得成功时,您将开始在绩效上失败。不好。
您有一个 message
实体。毫无疑问,它包含消息的文本、主题、时间戳、发件人、收件人以及构成原始消息一部分的其他属性。每条消息都有一个唯一的(主键)message_id
。但是实体不应包含 inbox
和 archive
等属性,因为这些属性与组织相关。
您需要一个 org
实体。每个组织都有一个唯一的org_id
、一个'name
和组织的其他属性。
那么你需要一个 org_message
table。它的主键包含 org_id
和 message_id
。它将包含像 archived
和 read
这样的布尔属性,以及一个命名其当前 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
INSERT INTO org_message (org_id, message_id, read, archived, folder)
VALUES (?, ?, ?, ?, ?) ON CONFLICT DO UPDATE;
设置或更新消息的组织属性
如果您发现搜索这些 table 太慢,您将需要索引。那是另一个问题的主题。