软考架构师故事系列-数据库系统

这是软考架构师的基础知识系列,我将枯燥的学习内容整理成生动的网文,希望能帮助到其他人更好的理解这些枯燥的知识,废话不多说。 here we go!

我是店长(数据库管理员DBA),你是来帮忙的伙计,咱们看看怎么用数据库把店管得井井有条。


1. 三级模式-两级映像:仓库、货架和小票

这个概念听起来高大上,其实就是咱们奶茶店的后台、前台和你手里的菜单。

  • 内模式(物理存储层) :这是咱们的后厨仓库。一箱箱牛奶堆在哪儿、珍珠粉圆放在第几个货架第三层,这是最底层的物理存放方式。你作为伙计不用管这个,这是我店长的事儿。

  • 模式(概念层) :这是我整理好的货架和配料表。我把仓库里的东西整理成一张张表:一张"原料库存表"、一张"饮品配方表"、一张"销售记录表"。你就知道咱们店里有什么,东西在"逻辑上"是怎么组织的。

  • 外模式(用户视图) :这是给你的收银机小屏幕 。我不会让你看到复杂的"原料成本价"和"供应商电话",只给你看"饮品名称"和"价格"。这就是专门为你这个"伙计角色"定制的视图

  • 两级映像(神奇的映射)

    • 模式/内模式映像 :假如我把珍珠从"第三层货架"搬到了"门口推车里"(修改了物理存储位置),我只需要改一下我脑中的"映射",你收银机上的"珍珠奶茶"照样能点,不受影响。这就是物理独立性
    • 外模式/模式映像 :假如我在后台把"饮品配方表"里加了"卡路里"一栏,但只要我不把它放到你的小屏幕上,你的操作界面一点没变。这就是逻辑独立性

2. 数据库设计:开分店六步曲

隔壁老王看咱们店火了,想加盟,咱们得给他一套标准流程,这就是数据库设计。

  1. 需求分析 :老王说,"我要能点单、能查库存、能看谁买得多。"我拿出小本本记下,画成数据流图 (钱怎么流、货怎么流),写成需求说明书
  2. 概念结构设计 :我把老王的需求画成一幅E-R图 (实体-联系图)。
    • 实体(长方形):就是人、事、物。比如"顾客"、"奶茶"、"订单"。
    • 属性(椭圆形):实体的特征。比如"顾客"有"电话"、"姓名"。
    • 联系(菱形) :实体之间的关系。比如顾客购买奶茶。
  3. 逻辑结构设计 :把E-R图这张画,翻译成电脑能懂的二维表格(关系模式 )。
    • 1:1联系:一个店长管一家店。店长和店的信息可以放一张表。
    • 1:N联系:一个顾客可以下多个订单。那把"顾客ID"放到"订单"表里。
    • M:N联系:一杯奶茶可以用多种配料,一种配料可以加到多种奶茶里。这可麻烦了,必须单独建一张"奶茶-配料表"。
  4. 物理设计:决定这些表格文件具体怎么存,放固态硬盘还是机械硬盘,怎么建索引让查"杨枝甘露"时更快。
  5. 数据库实施:真正在电脑上把表建起来,写个收银程序,让老王试营业。
  6. 运行和维护:开业后,发现"生椰拿铁"卖爆了,系统变慢,我再回来调优。

3. 关系代数:给表格做"拼图游戏"

你把表格当成积木,关系代数就是玩积木的手。

  • 选择(σ) :就是筛选行σ_{价格>15}(奶茶表) → "把价格超过15块的奶茶挑出来"。
  • 投影(π) :就是筛选列π_{品名,价格}(奶茶表) → "我只看品名和价格,别的列先藏起来"。
  • 连接(⋈) :就是拼图
    • 自然连接 :把"顾客表"和"订单表"里相同顾客ID的信息自动拼成一张大宽表,重复的ID列只留一列。
    • 笛卡尔积:不管你三七二十一,强行把A表的每一行和B表的每一行都拼一次。比如"奶茶表"有10行,"配料表"有5行,结果就是10×5=50行,很多是无意义的组合。

4. 函数依赖与范式:给表格"瘦身减肥"

一开始,我把所有信息写在一张大表里:

顾客名 电话 奶茶名 价格 店长名
张三 123 珍珠奶茶 15 老文
张三 123 杨枝甘露 20 老文

这表毛病可大了!

  • 1NF(第一范式) :要求每个格子里只能有一个值,不能是数组。如果张三点了两杯,不能写"珍珠奶茶,杨枝甘露",得拆成两行。上面这表满足1NF
  • 2NF(第二范式) :消除部分依赖
    • 主键应该是(顾客名,奶茶名)。
    • 但是!"电话"只依赖于"顾客名"(部分依赖),"价格"只依赖于"奶茶名"(部分依赖)。这不行!会造成数据冗余(张三电话存了两遍)和更新异常(奶茶涨价了要改N个地方)。
    • **拆!**拆成三个表:顾客表(顾客名, 电话)奶茶表(奶茶名, 价格)订单表(顾客名, 奶茶名)
  • 3NF(第三范式) :消除传递依赖
    • 假设奶茶表里有个字段叫店长名。我们知道:奶茶名 → 所属分店ID,然后所属分店ID → 店长名。这就是传递依赖。
    • 还是那个问题,店长升职了,得把所有含该店长的奶茶记录全改一遍。
    • **拆!**再拆出一个分店表(分店ID, 店长名)

经过2NF和3NF的减肥,数据就不冗余了,改一个地方就行。这就是规范化的意义。

5. 并发控制:两个人同时点同一杯奶茶

  • 丢失更新 :你和另一个伙计同时点"最后一杯杨枝甘露"的"已售罄"按钮。你先点了,系统记售罄;他后点了,他的操作把你的操作覆盖了,系统以为还没售罄,结果顾客下单后做不出来。**X锁(写锁)**可以解决:谁先点售罄,谁就锁住这条记录,别人改不了。
  • 读脏数据 :我已经点了售罄,库存变0。另一个伙计在查库存,看到是0,告诉顾客没了。顾客刚走,我突然发现点错了,回滚 了操作,库存又变回1。但顾客已经走了。二级封锁协议可以解决。
  • 不可重复读 :你查库存时杨枝甘露还有1杯。在你准备下单的几秒内,隔壁柜台线上下单抢走了这最后一杯。你再查,发现没了。你两次读取的数据不一致。三级封锁协议可以解决。

6. NoSQL(非关系数据库):当网红店遇到双十一

咱们店火了,一天卖100万杯,传统的关系型数据库(SQL)像记账先生,一笔笔记,虽然准确但速度跟不上了。这时需要NoSQL

  • 键值存储(Redis) :就像个大号的临时记事贴。顾客ID是Key,他刚加入购物车的东西是Value。查得飞快,用来做缓存,缓解后台数据库压力。
  • 文档存储(MongoDB) :就像顾客的朋友圈。有的发图,有的发视频,有的只发文字,结构不固定。用JSON格式存起来很方便,不用像SQL那样先定义好所有列才能存。
  • 列存储(HBase) :就像咱们分析销售报表。关系数据库是按"行"存的(张三、珍珠奶茶、15元、3月1日;李四、柠檬水、10元、3月2日...)。列存储是按"列"存的(把所有顾客名存一个文件,所有奶茶名存一个文件),做统计(比如计算奶茶平均价格)时,只读"价格"这一列,速度快得飞起。

7. 分布式数据库:从一家店到全国连锁

咱们的"奶茶店"越开越多,北京、上海、广州都有分店。数据全存总部一台电脑里肯定不行:广州分店查个库存,数据得从北京机房千里迢迢传过去,太慢了。于是我们搞起了分布式数据库------数据分开存放,但用起来像一家店。

新增的几种模式(在三级模式之外)

  • 全局概念模式 :这是咱们总部的大脑 。它定义整个连锁店所有的数据长什么样,比如"所有分店的顾客表都是(顾客ID,姓名,电话)"。对于广州分店的伙计来说,他感觉就像在操作一个统一的全国数据库,这就是数据透明性
  • 分片模式 :数据怎么切开存。比如我们按地区分:北京分店的销售记录存在北京服务器,广州的存广州。这叫水平分片 (按行分)。也可以垂直分片:顾客基础信息存一台机器,顾客的消费积分存另一台机器。
  • 分布模式:告诉系统,哪个分片具体放在哪台服务器上。比如"北京销售记录"放在IP为123的服务器上。

CAP理论:鱼与熊掌不可兼得

假设双十一期间,网络突然断了,北京和广州的服务器联系不上了。这时候你作为店长,得做一个痛苦的抉择:

  • C(一致性)所有门店数据绝对一致 。比如"买一送一"的优惠券总量必须精确。为了C,网络断了时,我宁愿暂时停掉所有分店的优惠券业务,直到网络恢复。这就是CP系统,牺牲了可用性。
  • A(可用性)系统永远能响应 。网络断了,广州店可以自己先发券,先记录着,等网络通了再告诉总部。此时北京和广州数据暂时不一致,但店能继续营业。这就是AP系统,牺牲了强一致性,追求最终一致性(BASE理论)。
  • P(分区容忍性)必须允许网络分区 。在分布式系统里,网络故障是常态,P基本是必须选的。所以真正的选择是在CP (保证一致性)和AP(保证可用性)之间二选一。

8. SQL语言:收银机上的操作命令

你每天在收银机上点点点,背后跑的都是SQL。它就是你跟数据库对话的"咒语",不区分大小写。

咱们以"奶茶店数据库"为例,手把手教你念咒语。

建表(开新账本)

sql 复制代码
CREATE TABLE 奶茶表 (
    奶茶号 CHAR(5) PRIMARY KEY,     -- 主键,不能重复不能空
    名称 CHAR(30) UNIQUE,           -- 名称唯一
    价格 INT,
    类型 CHAR(10)
);

查数据(最常用)

  • "给我看看所有'鲜果茶'类型的奶茶名称和价格。"
sql 复制代码
SELECT 名称, 价格 
FROM 奶茶表 
WHERE 类型 = '鲜果茶';
  • "我想按价格从贵到便宜排个序。"
sql 复制代码
SELECT * FROM 奶茶表 ORDER BY 价格 DESC;
  • "咱们一共有多少种不同类型的奶茶?"
sql 复制代码
SELECT 类型, COUNT(*) AS 种类数 
FROM 奶茶表 
GROUP BY 类型;

这里的GROUP BY就是把"鲜果茶"的放一堆,"奶茶"的放一堆,然后数每堆有几个。AS是起个别名,让结果更好懂。

增删改(操作数据)

  • "新出了一款'生椰冰咖',加进去。"
sql 复制代码
INSERT INTO 奶茶表 VALUES ('T006', '生椰冰咖', 18, '咖啡');
  • "珍珠奶茶涨价了,改成16块。"
sql 复制代码
UPDATE 奶茶表 SET 价格 = 16 WHERE 名称 = '珍珠奶茶';
  • "芝士葡萄卖得不好,下架吧。"
sql 复制代码
DELETE FROM 奶茶表 WHERE 名称 = '芝士葡萄';

高级一点的:连接查询

  • "我想看看'张三'这个人,都买过哪些奶茶。"这需要把顾客表订单表连起来查。自然连接NATURAL JOIN会根据相同的列名(比如都有顾客ID)自动匹配。
sql 复制代码
SELECT 顾客.姓名, 订单.奶茶名
FROM 顾客 NATURAL JOIN 订单
WHERE 顾客.姓名 = '张三';

相关推荐
骄马之死1 天前
SpringMVC + SpringBoot 核心知识点总结
java·spring boot·后端
GoGeekBaird1 天前
Anthropic技能"(Skills)的经验分享
后端
王码码20351 天前
多台服务器怎么统一看状态?Beszel 轻量监控,搭起来不费事
运维·服务器·后端·安全·阿里云·接口·web
刀法如飞1 天前
一文搞懂DDD 领域驱动设计思想原理
设计模式·架构·代码规范
郑洁文1 天前
基于Spring Boot的流浪动物救助网站
java·spring boot·后端·毕设·流浪动物救助
Cosolar1 天前
LlamaIndex 文档解析与分块策略深度解析
人工智能·面试·架构
指令集梦境1 天前
Cursor + Spring Boot实战:从零写一个RESTful API
spring boot·后端·restful
摇滚侠1 天前
Maven 入门+高深 单一架构案例 54-59
java·架构·maven·intellij-idea
caimouse1 天前
Reactos 第 4 章 对象管理 — 4.5 几个常用的内核函数
c语言·windows·架构
码云之上1 天前
聊聊如何设计一个高效、稳定的 Node.js 接入层
前端·后端·node.js