关于冗余设计的一点思考

模型设计,消除冗余

首先简单介绍一下数据库结构设计的范式:

  • 第一范式(1NF)
    强调的是列的原子性,即列不能够再分成其他几列。
    用于消除一列中存放多值可能产生的冗余情况。
    可以把常见的EXCEL表格中有合并单元格的那种直接排除了。
    举个例子,一个学生有班级和年级两个属性,那么就要设计两个列来放。
    (学生编号,年级,班级)
  • 第二范式(2NF)
    在第一范式基础上,增加两个条件:一是表必须有主键,二是没有包含在主键中的列必须完全依赖于主键,而不能只依赖于主键的一部分。
    第一条好理解,就是必须有一个唯一键用来做主键,可以是多个列的组合键。
    第二条举个例子,一个学生表(班级号,学号,学生姓名,班级名)的主键是(班级号+学号),如果该表有个列是班级名,那该表就不符合第二范式,因为班级别名仅依赖了主键中的班级号,而非完全依赖主键。此处班级别名即是冗余。应当拆分为班级表(班级号,班级名)、学生表(班级号、学号,学生姓名)。
  • 第三范式(3NF)
    在第二范式基础上,再增加条件:不能存在传递依赖。
    即不能存在:非主键列 A 依赖于非主键列 B,非主键列 B 依赖于主键的情况。
    举个例子,还是上面的学生表,对所有学生进行唯一编号后:学生表(学生编号,学生名字,班级号,班级名),这里学生编号是主键,其他列不可拆分且全部完全依赖学生编号,所以符合第二范式。但学生所在班级名字依赖于学生所在班级号,属于传递依赖,故不符合第三范式。应当拆分为学生表(学生编号,学生名字,班级号)和班级表(班级号,班级名)。
  • 其他范式
    即使符合第三范式依然还是可以产生冗余。如BCNF范式针对的是组合主键中的依赖关系,还有第四、五范式…不做延伸。

可以见得数据库范式的制定一直依赖追求的是在关系型结构下对空间的最优利用。

反模式,制造冗余

而空间和性能往往是相对,在实际的开发中,我们却经常特意制造一些冗余,以取得更好的性能。
接下来探讨下面的案例:一个聊天工具中的用户表,和用户的好友表。
用户表(用户ID,名称,头像,邮箱,手机号......)
好友表(用户ID,好友的用户ID,好友的名称,好友的头像)
这里的好友表是不符合第二范式的,因为我冗余了好友的名称、头像。这样当我在查询本人通讯录中的好友的时候就不需要连接用户表,甚至于我会将整个好友组缓存在一个内存的集合数据结构中。
而冗余带来的问题是数据同步问题。即“当好友修改了他的头像之后需要将好友表中的好友头像字段进行更新。”这里的同步仅仅是主从数据同步,冗余数据相当于缓存,因为无法依赖数据库完成数据同步,就用程序设计来处理,这里通常的解决方法是使用面向对象中的订阅模式。当好友对象产生的时候订阅用户的属性变更,于是当变更发生的时候可以响应处理数据同步。大多数消息队列都对该模式提供了很好的服务。这里的“数据同步”中的同步并不是“异步编程”中的同步的意思,冗余数据的同步实质上是异步进行的,需要允许一定程度上的实时性、可靠性缺失。
行到这里,我们的聊天工具已经可以很好地响应通讯录上小伙伴们的头像、名称修改了。梳理一下做法,首先是使用面向对象方法,将表转化为实体类,数据行转化为实例对象,列作为对象的属性,属性的修改即“写”权仅掌握在该实例对象手中,而其被其他实体的引用作为冗余副本通过订阅来更新。

回归现实,接受冗余

继续上面的好友表例子。
是的,我拥有了一个能及时响应好友变化的通讯录。而且我还有一个很喜欢换头像以及名字的好友,所以我经常会认不出我的好友究竟谁是谁。
于是我的产品经理提议增加一个备注的功能,多么妙的设定!于是我头脑中的好友画像通过备注,这个美妙的功能,跟通讯录中常常变换的头像建立了联系。
然而,剧情推进,在第二个大版本更新的时候我们的聊天工具加入了群聊,于是陌生人出现了。那些群友,并不在我的通讯录中,他们的头像也是常常变化的,OMG。那些陌生的群友就好像柯南中的黑影,我根本放弃了去取分谁是谁是谁在发言。
于是我天才的产品经理说:需要给群成员增加一个备注功能!
“異議あり!”
我马上反对了这个提议,一般的群成员名主键应该是(群ID+用户ID),而我对群成员备注的话主键则是(我的用户ID+群ID+群成员的用户ID),可是我的需求是对陌生人增加备注,主键是(我的用户ID+陌生人的用户ID)。一般做法中的群成员名只有在群规严格的群中才有用,而后两者基本可以说离谱了,无论哪一种其实都不好满足我的需求。
那么,我们现实中是怎么面对陌生人的呢?还是得对陌生人在脑中建立画像吧,这画像就像是对陌生人的部分信息的浅拷贝,就是冗余。而冗余的更新不是被动的订阅响应,是由我主动观察所得。此时,冗余副本的更新即“写”的主动权掌握在了“我”这个实例手中。
回到对陌生群友的处理。先增加一份陌生人数据实体类型(或者说表),与好友表冗余的用户基本信息相同,不同的是并不订阅其用户基本信息的变更而且不展示在通讯录上。于是,作为用户的我,就能看到一个头像、名字并不乱变的陌生人。那么什么时候应该同步呢,就是在“我”下次决定好好观察下这个陌生人的时候,也就是当我下次点开陌生人的名片的时候。由于是用户的主动行为,陌生人在用户脑中的画像能很好地更新与陌生人新头像之间的关联。
我的产品经理似乎快被我说服了,但他还是有点不服气。
好吧,系统设计的系统分析中有一个环节是对现有系统的分析,包括当前同类产品尤其龙头的分析。我们一起来看看张小龙是怎么做的吧。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,377评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,390评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,967评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,344评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,441评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,492评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,497评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,274评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,732评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,008评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,184评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,837评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,520评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,156评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,407评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,056评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,074评论 2 352

推荐阅读更多精彩内容