1

MYSQL/PHP,我想创建人们在网站上执行的活动的记录。

Table ADDED -> EventID, UserID, Time, IP

Table DELETED -> EventID, UserID, Time, IP

Table SHARED -> EventID, UserID, Time, IP.

在查询以读取例如由 a 执行的最后 10 个操作时加入这些表是否更有效USERID,或者像这样的结构会更有效。

Table EVERYTHING -> EventID, EventType(eg ADDED, DELETED, SHARED), UserID, Time, IP 
4

2 回答 2

3

使用一个记录所有事件并区分事件类型的表,如您的第二个建议。

您在此处仅存储一种类型的数据,因此将其存储在一个表中是合适的。在早期阶段,您不必太担心表格会随着时间的推移而增长到多大。像这样的表中只有几列,在您甚至需要考虑对其进行分区之前,它很容易增长到数百万行。

如果您的事件类型数量有限,您可以考虑使用列ENUM()数据类型EventType

于 2012-05-18T01:52:40.673 回答
1

使用一张表是正确的做法,因为它已正确规范化。添加新事件类型不需要新表。维护参照完整性并利用索引为用户检索和排序所有事件也容易得多。(如果您将它们放在单独的表中,获取用户的所有事件并按时间排序可能比使用一张表要慢得多!)

但是,有一些方法可以使这些表更小,以节省空间并保持索引小:

  • 使用 anenum()来定义您的事件类型。如果您有少量事件,则每行最多使用一个字节。
  • 使用整数类型从相同数量的字节UNSIGNED中获取更多EventID和s。UserID
  • 如果您不需要完整的日期范围(可能),请使用 TIMESTAMP 类型与 DATETIME 类型相比,每行节省 4 个字节。
  • 如果您只使用 ipv4 地址,请将 IP 存储为无符号 4 字节整数并使用 INET_ATON() 和 INET_NTOA() 来回转换。这是最大的赢家:VARCHAR 类型至少需要 16 个字节,并且您可能会使用固定的行长度格式。

我推荐这样的表格格式:

CREATE TABLE Events (
    `EventID` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
    `UserID` MEDIUMINT UNSIGNED NOT NULL COMMENT 'this allows a bit more than 16 million users, and your indexes will be smaller',
    `EventType` ENUM('add','delete','share') NOT NULL,
    `Time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `IP` INTEGER UNSIGNED NOT NULL DEFAULT 0,
    PRIMARY KEY (`EventID`),
    FOREIGN KEY (`UserID`) REFERENCES `Users` (`UserId`) ON UPDATE CASCADE ON DELETE CASCADE,
    KEY (UserID)
);

如果您使用 MyISAM 存储它,您的行长度将为 16 字节,使用固定格式。这意味着每百万行需要 16MB 的数据空间,而索引可能需要一半的空间(取决于您使用的索引)。这非常紧凑,mysql 可能大部分时间都可以将表的整个工作部分保存在内存中。

然后是创建最常见操作所需的索引的问题。例如,如果您始终显示某个用户在某个时间范围内的所有事件,请替换KEY (UserID)INDEX userbytime (UserID, Time). 然后类似的查询SELECT * FROM Events WHERE UserID=? AND Time BETWEEN ? AND ?会非常快。

于 2012-05-18T04:15:41.697 回答