赞
踩
在阅读了
this great Nettuts+ article的提示之后,我提出了一个表格模式,它将高度易失的数据与其他遭受严重读取的表进行分离,同时降低整个数据库模式所需的表数,但是我不是肯定这是一个好主意,因为它不遵循正常化规则,我想听听你的意见,这里是一般的想法:
我有四种类型的用户建模在Class Table Inheritance结构中,在主“用户”表中,我存储所有用户(id,用户名,密码,几个标志,…)常用的数据以及一些TIMESTAMP字段(date_created, date_updated,date_activated,date_lastLogin,…)。
从上面提到的Nettuts文章中引用第16个提示:
Example 2: You have a “last_login”
field in your table. It updates every
time a user logs in to the website.
But every update on a table causes the
query cache for that table to be
flushed. You can put that field into
another table to keep updates to your
users table to a minimum.
现在它变得更加棘手,我需要跟踪一些用户统计信息
>看到用户个人资料的唯一次数
>点击特定类型的用户的广告有多少个独特时间
>看到特定类型用户的帖子有多少个独特时间
>等等…
在我的完全规范化的数据库中,这加起来约8到10个额外的表,这不是很多,但是我希望保持简单,如果可以的话,所以我已经提出了以下“事件”表:
|------|----------------|----------------|---------------------|-----------|
| 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 |
|------|----------------|----------------|---------------------|-----------|
基本上,ID是指TABLE表中的主键(id)字段,我相信其余的应该很简单。我在这个设计中喜欢的一件事是,我可以跟踪所有的用户登录而不是最后一个,从而生成一些有趣的数据。
由于事件表的性质不断增长,我也考虑进行一些优化,如:
>#9:由于只有有限数量的表和有限(和预定)数量的事件,TABLE和EVENTS列可以被设置为ENUM而不是VARCHARs以节省一些空间。
>#14:使用INET_ATON()而不是VARCHAR将IP存储为UNSIGNED INT。
>将DATE存储为TIMESTAMP而不是DATETIME。
>使用ARCHIVE(或CSV?)引擎,而不是InnoDB / MyISAM。
>只支持INSERT和SELECT,数据被即时压缩。
总的来说,每个事件只消耗14(未压缩)字节,这对我的流量来说是可以的。
优点:
>能够存储更详细的数据(如登录)。
>不需要设计(和代码)几十个额外的表(日期和统计数据)。
>减少每个表的几列,并保持易失性数据的分离。
缺点:
>非关系(仍然不如EAV):
> SELECT * FROM events WHERE id = 2 AND table =’user’ORDER BY date DESC();
>每个事件(ID,TABLE和EVENT)6个字节开销。
我更倾向于使用这种方法,因为职业者似乎远远超过了缺点,但我仍然有点不情愿…我错过了什么?你有什么想法?
谢谢!
@coolgeek:
One thing that I do slightly
differently is to maintain an
entity_type table, and use its ID in
the object_type column (in your case,
the ‘TABLE’ column). You would want to
do the same thing with an event_type
table.
只是为了清楚,你的意思是我应该添加一个额外的表,映射表中允许哪些事件,并在事件表中使用该表的PK,而不是有一个TABLE / EVENT对?
@ben:
These are all statistics derived from
existing data, aren’t they?
附加表主要与统计信息相关,但我的数据不存在,一些示例:
user_ad_stats user_post_stats
------------- ---------------
user_ad_id (FK) user_post_id (FK)
ip ip
date date
type (impressed, clicked)
如果我放弃这些表,我无法跟踪谁,什么或什么时候,不知道如何看法可以帮助这里。
I agree that it ought to be separate,
but more because it’s fundamentally
different data. What someone is and
what someone does are two different
things. I don’t think volatility is so
important.
我听说过这两种方式,我在MySQL手册中找不到任何东西,说明任一个都是对的。无论如何,我同意你们分开的表格,因为它们代表了数据的种类(附加的好处比一般的方式更具描述性)。
I think you’re missing the forest for
the trees, so to speak.
The predicate for your table would be
“User ID from IP IP at time DATE
EVENTed to TABLE” which seems
reasonable, but there are issues.
我的意思是“不如EAV”,所有记录都遵循线性结构,它们很容易查询,没有层次结构,所以所有查询都可以用简单的SELECT来完成。
关于你的第二个声明,我想你在这里理解我错了IP地址不一定与用户相关联。表结构应该如下所示:
IP address (IP) did something
(EVENT) to the PK (ID) of the
table (TABLE) on date (DATE).
例如,在上面我的例子的最后一行应该读取IP 217.0.0.1(某些管理员),删除用户#2(最后一个已知的IP为127.0.0.2)在2010-04-20 03:20:00 。
You can still join, say, user events
to users, but you can’t implement a
foreign key constraint.
的确,这是我的主要关切。然而,我并不完全确定这种设计可能会出错,传统的关系设计不会出错。我可以发现一些注意事项,但只要应用程序搞乱数据库知道它在做什么,我猜不应该有任何问题。
在这个争论中,另外一件事就是我会存储更多的事件,每个事件比原来的设计多一倍,在这里使用ARCHIVE存储引擎是非常有意义的,支持FK(既不是UPDATE或DELETE)。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。