查看原文
其他

张大胖学数据库

2016-12-05 刘欣 码农翻身

从这学期开始,张大胖开始学习数据库, 听说这门课很重要, 很基础, 但是大胖学的很烦。


其实刚开始的时候还行, 课程先讲了讲数据库的作用, 他听的津津有味, 但讲到后边, 当那些文绉绉的术语像关系演算、函数依赖、规范化......  出现的时候,  大胖彻底的懵了。  


他实在是不明白, 这个看起来像一个表格的东西为什么搞这么多数学的公式, 最烦数学了。


周末大胖跑去向大神好基友Bill诉苦 :“这关系数据库不就是一个二维的表格吗, 就像Excel那样, 一行一列的, 为什么搞的这么复杂, 还有数学的东西?”


Bill 笑了笑说: “看起来确实像个表格, 但是和表格很不一样, 你看看这个例子, 然后想想能直接用关系数据库来保存吗?”

(表格1 订单表 )


大胖说: “似乎不行,你看一个订单号X2001对应一个用户,U001(白展堂),  还对应两行产品, P101(路由器), P102(充电宝) , 不过, 我能不能改成这样: ”

(表格2 点击看大图)


Bill一看, 这张大胖竟然把多行合并成了一行, 中间用逗号分开, 不由的又气又笑:

“你要是参加工作了, 设计出这样的数据库表, 老板非骂死你不可。  你要记住呀, 我们关系数据库最忌讳的就是在一个单元格里存储多个值。 这是典型的‘非规范化’的设计”


“非规范化?  那怎么办? ”


“拆分, 把它拆成规范化的 ” 说着,Bill 搞了两个表格出来:


(表3: 订单表)

(表4: 订单细节表)


“明白了, 这样的拆分就可以保证一个单元格只有个值了” 张大胖说。


“这种形式的表, 我们就叫做第一范式,  不止如此, 你看看表格3 订单表, 是不是一个订单号就能唯一的确定一行? ”


“对, 订单表确实是这样的, 但是表格4 单单用订单号就不行了, 还得加上产品编码, 才能确定同一行的其他值。”


Bill 说: ”所以我们说表3的主键是 (订单号), 表4的主键是(订单号,产品编码), 这是一个复合主键“


大胖高兴的说: “啊, 这第一范式看来很简单嘛”


“别急, 你再看看表格4:订单细节表, 虽然说 (订单号,产品编码) 是主键, 能确定其他属性的值, 但是 产品名称和单价  实际上并不依赖于 订单号。  如果我们想添加一个新的产品比如ipad, 你会发现没法放入这张表, 因为没有订单号!


“奥, 必须先有订单才能有产品, 这确实是太扯了, 难道再拆分?” 大胖问?


“必须拆, 要不然就没法工作”

(表4.1  订单细节表)

(表4.2 产品表)


“我明白了, 现在表4.1 中主键还是(订单号,产品编码),  剩下的属性(数量)肯定依赖于这个主键了, 表4.2也类似。”


Bill总结说:“这种所有属性仅仅依赖于主键的情况就是 第二范式 。


“这些范式术语听起来一本正经的, 很学究, 背后还是挺有用的嘛。 那表格3中主键是(订单号), 其他所有属性都依赖于主键, 已经是第二范式了吧”


Bill 说 :“可以这么认为, 但是这个表有个好玩的情况,  就是订单号能决定用户ID, 而用户ID 能决定用户名称, 这就出现了传递依赖:  订单号->用户ID->用户名称。  你看看用户信息其实也无法单独管理了, 也得拆分, 这个很简单, 你来试试? ”


张大胖迅速的鼓捣出两张表来:

(表3.1  订单表)

(表3.2  用户表)


Bill说:“不错, 现在就没有传递依赖了,  我们可以称之为 第三范式 了”


“我有个疑问啊” 大胖问道, ”为了满足所谓的范式要求, 我们把最初的大表拆的如此‘分散’, 到时候查询的时候岂不非常麻烦??“


“可不是, 把这些‘分散表’连接(Join)起来才能形成最初的那张表,  如果在数据量特别巨大的时候, 这种连接挺耗时的。 在实践中我们有时候不得不违反范式,做点数据的冗余。 比如说我们虽然把表3.2 用户表单独拆分了出来,  但是有时候为了性能, 还会在表3.1 中把用户名也加上, 为一个冗余。 ”


相关文章:

小李的数据库之旅(上)

小李的数据库之旅(下)

张大胖学socket

张大胖学递归


你看到的只是冰山一角, 更多精彩文章,尽在“码农翻身” 微信公众号, 回复消息"m"或"目录" 查看更多文章


有心得想和大家分享? 欢迎投稿 ! 我的联系方式:微信:liuxinlehan  QQ: 3340792577


公众号:码农翻身

“码农翻身”公众号由工作15年的前IBM架构师创建,分享编程和职场的经验教训。


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存