【问题标题】:Database efficiency/structure issue数据库效率/结构问题
【发布时间】:2012-04-27 20:08:15
【问题描述】:

我正在我正在创建的网站上编写电子邮件系统的简化版本。

基本前提是用户可以在网站上互相发消息,最好的例子是 ebay,你可以在网站本身上给其他用户发消息,它基本上充当电子邮件系统。

我所拥有的是消息本身、来自谁、发给谁以及文本。

我还希望有基本的“已读/未读”和“已删除”,甚至可能是“已发送”类别。

类似这样的:

表结构:

id、to、from、subject、body、dateTime

我想知道的是,在该表中添加“已读”和“已删除”列并搜索这些特定条件是否更有意义,当我在网站上需要它们时,或者如果它有另一个“类别”表然后有一个连接表放置一个带有类别 ID 的消息 ID,然后使用该连接表在请求时提供信息是更有效/最佳实践吗?

如果我的问题没有意义,请原谅我,我对这些东西还是很陌生。

【问题讨论】:

    标签: php mysql database normalization


    【解决方案1】:

    我会添加两列:

    read tinyint(1),
    deleted tinyint(1)
    

    并将它们用作布尔值。

    【讨论】:

    • 我现在非常倾向于这种方式,我主要担心的是用户群的潜在范围非常大,我说的是数十万用户。我只是有点担心速度以及这种方式的查询如何在可能非常高的负载下运行。到目前为止,我做过的所有其他网站的用户都不超过 3 个,都是管理员,所以这些类型的问题对我来说是新的。因此,渴望在第一时间就做好。
    • 你可以做一些事情,比如有一个规格表,但这只会减慢查询速度,因为简单的 1 或 0 小于简单的 1 或 0 以及对消息的引用。它也将更快,因为不需要加入。
    • 我已经从每个人那里得到了一些很好的建议,但我想我会选择这个,它至少对我来说是最简单和最快的,尽管@Pierre-Olivier 的建议可能会结束如果项目进一步发展,从长远来看会更有用。谢谢大家!
    【解决方案2】:

    我刚刚实现了类似的东西。我将该列放在“消息”表中。我选择了以下:

    ReadDate DATETIME DEFAULT NULL,
    

    如果消息尚未被阅读,ReadDate 为 NULL。用户阅读后,我填写阅读日期。这允许发送者知道接收者何时读取它。

    【讨论】:

    • 当你将它移动到deletedMEssages 表时,你是否保留了所有相同的信息,除了现在消息被“删除”了吗?从长远来看,我的目标是,如果人们这样选择,他们可以将其移回,或者如果他们不小心删除了某些内容,如果他们仍然需要,他们仍然可以看到这些内容。
    • @DavidMorin,我删除了这部分答案,因为我意识到您将已删除的内容更像是另一个文件夹(意外删除的常见实现)。就我而言,我说的是归档。我的存档消息被移动到具有相同架构和一个“DeletedDate”列的 DeletedMessages 表中。考虑到它会在阅读消息时提高性能,它仍然可能适合您使用。删除时会慢一些。
    【解决方案3】:

    我将为这个系统创建三个表。一个用于您的线程(一组消息),一个用于您的实际消息,另一个用于您的类别。

    类似的,

    MessagesThreads
    --------------------
    id (int, serial)
    from (int, foreign: Users.id)
    to (int, foreign: Users.id)
    subject (varchar)
    category (foreign key: Categories.id)
    
    MessagesContent
    --------------------
    id (int, serial)
    threadId (int, foreign: MessagesThreads.id)
    content (text)
    date (datetime)
    status (tinyint) (0 for unread, 1 for read, 2 for deleted, for instance)
    
    Categories
    --------------------
    id (int, serial) 
    name (varchar)
    

    这将是一个正确规范化的数据库。

    这样,一个线程可以包含一对多的消息(因为外键在MessagesContent),一条消息只附加到一个线程上,一个线程可以有一个类别。

    根据您的规范,我认为这是存储消息的最有效方式。

    【讨论】:

    • 这很有帮助,如果我在做一个“论坛风格”的消息系统,这将是有意义的。我对这个小家伙的目标是更多的电子邮件风格,所以基本上我给你发消息,当你给我发回消息时,它将是另一封“电子邮件”,电子邮件的正文将包含文本已经来回发送了,就像回复之类的东西一样。
    • @DavidMorin 这与数据的实际存储方式无关。之前的邮件是否出现取决于您是否查询之前的邮件。此外,具有该功能的电子邮件系统实际上会复制数据并将其发送到附有回复的新电子邮件中。
    • 我的架构旨在实际上避免在每封电子邮件/消息中重复消息内容。我设计它是为了记录讨论/以前的消息。在我看来,在每个回复中重复消息内容可能不是长期的最佳解决方案。您的数据库将很快变大。
    • @Pierre-OlivierBourgeois 当您单击“回复”时,我没有发现将电子邮件数据复制到新电子邮件中的问题。如果它没有被复制 - 你是说你应该引用它?那么,如果原件被更改,会发生什么?所有引用(回复)都会回复不同的内容。
    • 你会简单地做SELECT <...> FROM MessagesContent WHERE threadId = discussion ORDER BY date DESC 吗?这将为您提供按日期排序的特定讨论(电子邮件组)的所有消息?
    【解决方案4】:

    给定这样的用户帐户表:

    CREATE TABLE tbl_accounts(
        id INT NOT NULL AUTO_INCREMENT,
        PRIMARY KEY(id),
        email_addr VARCHAR(50) NOT NULL,
        passkey BLOB /* AES KEY */
    ) ENGINE = InnoDB;
    

    您将需要一个邮箱表来根据用户帐户和他们正在检查的文件夹(收件箱|发件箱)查找电子邮件。我们将这张表分开,保持数据库“标准化”。

    CREATE TABLE tbl_email_box(
        account_id INT, /* owner|sender of mail */
        FOREIGN KEY (account_id) REFERENCES tbl_accounts(id) ON DELETE SET NULL,
        email_id INT,
        FOREIGN KEY (email_id) REFERENCES tbl_emails(id) ON DELETE SET NULL,
    
        folder TINYINT(1), /* 0=inbox->account=owner; 1=outbox->account=sender; */
    
        status TINYINT(1) DEFAULT 0, /* 0=unread, 1=read */
    
        date TIMESTAMP     /* because the query executes when they check/send mail, */
                           /* then record is created (date=sent|received date) */
    ) ENGINE = InnoDB;
    

    此表将存储实际的电子邮件数据

    CREATE TABLE tbl_emails(
        id INT NOT NULL AUTO_INCREMENT,
        PRIMARY KEY(id),
        subject VARCHAR(100),
        message BLOB,
        created TIMESTAMP
    ) ENGINE = InnoDB;
    

    希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 2012-04-18
      • 1970-01-01
      • 2013-01-20
      • 2015-06-18
      • 2011-03-19
      • 1970-01-01
      相关资源
      最近更新 更多