数据库 - 设计"事件"表

Ali*_*xel 26 mysql database database-design partitioning relational

在阅读了这篇伟大的Nettuts +文章的提示之后,我想出了一个表模式,它可以将高度易变的数据与其他表进行大量读取分离,同时降低整个数据库模式中所需的表数,但是我我不确定这是不是一个好主意,因为它不符合规范化的规则,我想听听你的意见,这里是一般性的想法:


我有四种类型的模拟用户的类表继承结构,在主"用户"表我常用的数据存储到所有用户(id,username,password,数flags,...)与一些一起TIMESTAMP字段(date_created,date_updated,date_activated,date_lastLogin,. ..).

引用上面提到的Nettuts +文章中的#16提示:

示例2:表中有"last_login"字段.每次用户登录网站时它都会更新.但是表上的每次更新都会导致刷新该表的查询缓存.您可以将该字段放入另一个表中,以将用户表的更新保持在最低限度.

现在它变得更加棘手,我需要跟踪一些用户统计信息

  • 有多少独特的用户配置文件中看到时代
  • 多少唯一一个多次从广告特定类型的用户进行点击
  • 多少唯一一个多次从后特定类型的用户看到
  • 等等...

在我完全规范化的数据库中,这增加了大约8到10个额外的表,这不是很多但是如果可以的话我想保持简单,所以我想出了以下" events"表:

|------|----------------|----------------|---------------------|-----------|
| ID   | TABLE          | EVENT          | DATE                | IP        | 
|------|----------------|----------------|---------------------|-----------|
| 1    | user           | login          | 2010-04-19 00:30:00 | 127.0.0.1 |
|------|----------------|----------------|---------------------|-----------|
| 1    | user           | login          | 2010-04-19 02:30:00 | 127.0.0.1 |
|------|----------------|----------------|---------------------|-----------|
| 2    | user           | created        | 2010-04-19 00:31:00 | 127.0.0.2 |
|------|----------------|----------------|---------------------|-----------|
| 2    | user           | activated      | 2010-04-19 02:34:00 | 127.0.0.2 |
|------|----------------|----------------|---------------------|-----------|
| 2    | user           | approved       | 2010-04-19 09:30:00 | 217.0.0.1 |
|------|----------------|----------------|---------------------|-----------|
| 2    | user           | login          | 2010-04-19 12:00:00 | 127.0.0.2 |
|------|----------------|----------------|---------------------|-----------|
| 15   | user_ads       | created        | 2010-04-19 12:30:00 | 127.0.0.1 |
|------|----------------|----------------|---------------------|-----------|
| 15   | user_ads       | impressed      | 2010-04-19 12:31:00 | 127.0.0.2 |
|------|----------------|----------------|---------------------|-----------|
| 15   | user_ads       | clicked        | 2010-04-19 12:31:01 | 127.0.0.2 |
|------|----------------|----------------|---------------------|-----------|
| 15   | user_ads       | clicked        | 2010-04-19 12:31:02 | 127.0.0.2 |
|------|----------------|----------------|---------------------|-----------|
| 15   | user_ads       | clicked        | 2010-04-19 12:31:03 | 127.0.0.2 |
|------|----------------|----------------|---------------------|-----------|
| 15   | user_ads       | clicked        | 2010-04-19 12:31:04 | 127.0.0.2 |
|------|----------------|----------------|---------------------|-----------|
| 15   | user_ads       | clicked        | 2010-04-19 12:31:05 | 127.0.0.2 |
|------|----------------|----------------|---------------------|-----------|
| 2    | user           | blocked        | 2010-04-20 03:19:00 | 217.0.0.1 |
|------|----------------|----------------|---------------------|-----------|
| 2    | user           | deleted        | 2010-04-20 03:20:00 | 217.0.0.1 |
|------|----------------|----------------|---------------------|-----------|
Run Code Online (Sandbox Code Playgroud)

基本上是ID指表中的主键(id)字段TABLE,我相信其余部分应该非常简单.我在这个设计中喜欢的一件事是,我可以跟踪所有用户登录而不是最后一个用户登录,从而生成一些有趣的指标与该数据.

由于events表的性质不断增长,我还考虑进行一些优化,例如:

  • #9:由于只有有限数量的表和有限(和预定)数量的事件,因此可以将TABLEEVENTS列设置为ENUMs而不是VARCHARs以节省一些空间.
  • #14:存储IPS作为UNSIGNED INT小号INET_ATON(),而不是VARCHAR秒.
  • DATETIMESTAMPs存储s而不是DATETIMEs.
  • 使用ARCHIVE(CSV)引擎代替InnoDB/ MyISAM.
    • 仅支持INSERTs和SELECTs,并且动态压缩数据.

总的来说,每个事件只会消耗14个(未压缩的)字节,这对我的流量来说是可以接受的.

优点:

  • 能够存储更详细的数据(例如登录).
  • 无需十几个附加表(日期和统计数据)设计(和编码).
  • 减少每个表的几列并保持易失性数据分离.

缺点:

  • 非关系型(仍然不如EAV):
    • SELECT * FROM events WHERE id = 2 AND table = 'user' ORDER BY date DESC();
  • 6个字节每个事件开销(ID,TABLEEVENT).

我更倾向于采用这种方法,因为专业人士似乎远远超过缺点,但我仍然有点不情愿...... 我错过了什么?你对此有何看法?

谢谢!


@coolgeek:

我做的一件事略有不同,就是维护一个entity_type表,并在object_type列中使用它的ID(在你的情况下,就是'TABLE'列).您可能希望使用event_type表执行相同的操作.

为了清楚起见,你的意思是我应该添加一个额外的表来映射表中允许哪些事件,并在事件表中使用该表的PK而不是TABLE/ EVENTpair?


@ben:

这些都是从现有数据中得出的统计数据,不是吗?

附加表主要与统计相关,但我的数据尚不存在,例如:

user_ad_stats                          user_post_stats
-------------                          ---------------
user_ad_id (FK)                        user_post_id (FK)
ip                                     ip
date                                   date
type (impressed, clicked)
Run Code Online (Sandbox Code Playgroud)

如果我放弃这些表格,我无法跟踪谁,什么或何时,不确定视图如何在这里提供帮助.

我同意它应该是分开的,但更多的是因为它是根本不同的数据.有人是谁,有人做了两件事.我不认为波动性如此重要.

我已经听过两种方式,我在MySQL手册中找不到任何一种说法是正确的.无论如何,我同意你的看法,它们应该是分开的表格,因为它们代表了各种数据(除了常规方法之外,它还具有更多的描述性).

可以这么说,我觉得你错过了树林.

您的表的谓词将是"在DATE EVENTed to TABLE时从IP IP发送的用户ID",这似乎是合理的,但存在问题.

我的意思是"没有EAV那么糟糕"是所有记录都遵循线性结构,并且它们很容易查询,没有层次结构,因此所有查询都可以通过简单的方式完成SELECT.

关于你的第二个陈述,我想你在这里理解我错了; IP地址不一定与用户相关联.表结构应该是这样的:

IP地址(IP)在date()上对table()EVENT的PK ()做了一些事情().IDTABLEDATE

例如,在上面示例的最后一行中,它应该读取IP 217.0.0.1(某些管理员),在2010-04-20 03:20:00删除用户#2(其最后已知IP为127.0.0.2) .

您仍然可以将用户事件加入用户,但无法实现外键约束.

的确,这是我的主要关注点.但是我并不完全确定这种设计会出现什么问题,传统的关系设计不会出错.我可以发现一些警告,但只要应用程序搞乱数据库知道它在做什么我猜应该没有任何问题.

在这种说法计数了一个其他的事情是,我会存储更多的活动,而且每次都会多比原设计的双,它非常有意义的事件使用ARCHIVE此存储引擎,唯一的一点是它不支持FKs(UPDATEs或DELETEs).

coo*_*eek 5

我强烈推荐这种方法。由于您可能对 OLTP 和 OLAP 使用相同的数据库,因此通过添加一些星星和雪花可以获得显着的性能优势。

我有一个社交网络应用程序,目前有 65 张桌子。我维护一个表来跟踪对象(博客/帖子、论坛/线程、图库/相册/图像等)视图,另一个表用于对象推荐,第三个表用于总结十几个其他表中的插入/更新活动。

我做的稍微不同的一件事是维护一个entity_type表,并在object_type列中使用它的ID(在您的例子中,是“TABLE”列)。您可能希望对 event_type 表执行相同的操作。

澄清 Alix - 是的,您维护一个对象的引用表和一个事件的引用表(这些将是您的维度表)。您的事实表将包含以下字段:

id
object_id
event_id
event_time
ip_address
Run Code Online (Sandbox Code Playgroud)