张大胖学数据库

张大胖在学习数据库过程中遇到困难,好友Bill通过实际案例解释了如何将非规范化的表格转换为符合第一、第二及第三范式的表格,并讨论了在实际应用中可能会遇到的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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


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


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


周末大胖跑去向大神好基友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

张大胖学递归


from: http://chuansong.me/n/1246048751921

### 数据库视图与索引的概念 #### 视图 视图是一种虚拟表,其内容由查询定义。它并不实际存储数据,而是基于 SQL 查询动态生成结果集[^3]。创建视图的语法如下: ```sql CREATE VIEW view_name AS SELECT column1, column2, ... FROM table_name WHERE condition; ``` 修改视图可以通过 `ALTER VIEW` 实现,而删除视图则使用 `DROP VIEW` 命令。 视图的主要特点是不存储任何物理数据,仅保存查询逻辑。因此,每次查询视图时,都会重新执行定义该视图的 SQL 语句[^3]。 #### 索引 索引是数据库中一种特殊的数据结构,用于加速数据检索过程。通过在表的一列或多列上创建索引,可以显著提高查询效率[^1]。然而,在多列索引的情况下需要注意,只有当查询条件涉及索引的第一个字段时,才能有效利用此索引[^2]。 创建索引的基本语法为: ```sql CREATE INDEX index_name ON table_name (column1, column2, ...); ``` --- ### 数据库视图与索引的区别 | **对比维度** | **视图** | **索引** | |--------------------|---------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------| | **功能定位** | 提供了一种逻辑上的数据展示方式,简化复杂查询并增强安全性[^3] | 加速数据检索速度,减少磁盘 I/O 和扫描时间 | | **存储特性** | 不存储实际数据,只保存查询逻辑 | 存储指向记录位置的信息 | | **性能影响** | 可能降低写入性能(因需维护视图关联的基础表),但不影响读取 | 虽然提高了查询性能,但也增加了插入、更新和删除操作的成本 | | **适用场景** | 需要隐藏部分敏感信息或将多个表联合起来呈现给最终用户的场合 | 经常需要按某些字段快速查找记录的情况 | --- ### 应用场景分析 #### 视图的应用场景 - 当希望向用户提供经过筛选后的特定数据子集而非整个原始表格时,可采用视图来实现这一目标。 - 对于那些频繁使用的复杂 JOIN 或聚合运算,预先定义好相应的视图有助于简化后续开发工作流[^3]。 #### 索引的应用场景 - 在高并发读取环境中,针对经常被用来过滤或排序的关键字建立合适的索引能够极大改善用户体验。 - 若某张大表存在大量重复值,则考虑为其设置唯一性约束或者哈希类型的索引来避免冗余存储空间浪费问题。 --- ### 总结说明 尽管两者都旨在优化数据库交互体验方面发挥重要作用,但从本质上讲它们解决的是完全不同的两类需求——即如何更好地组织展现现有资源以及怎样更迅速地获取所需条目之间的差异所在。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值