📝 物理设计与实施 · 习题课

📚 第14章配套练习 ⏱️ 预计 50 分钟 💻 含 SQL 实操题 🎯 期末重点
🎯 本节练习目标
  • 能为字段选择 合适的数据类型(实操必考)
  • 能判断 哪些字段该建索引(必考核心)
  • 能根据关系模式 写出 CREATE TABLE(综合大题)
  • 掌握数据库实施步骤、运维工作的考点

📌 答题前先看:物理设计三件套

🎯 物理设计三步走
  1. 选数据类型:每个字段问自己 —— 是数字还是文字?长度固定吗?需要多大范围?
  2. 定约束:主码?外码?非空?默认值?
  3. 建索引:主码必建;查得多的、连接的建;改得多、取值少的不建。
⚠️ 三个最容易踩的坑

金额用 DECIMAL,绝不用 FLOAT(浮点数会丢精度)

身份证号、手机号用 CHAR,绝不用 INT(超出 INT 范围 + 开头 0 会丢)

"性别"这种取值少的字段不要建索引(区分度太低,没用)

📝 第一部分 · 概念巩固10 分钟

先用几道选择题把核心概念过一遍。

练习 1.1 ⭐⭐ 必考 索引判断

下列字段中,最适合 建立索引的是?

📖 查看答案

✅ 答案:B

分析:

A 错:性别只有男/女,区分度太低,索引基本没用

B 对:用户编号是外键 + 频繁查询条件,正是建索引的最佳场景

C 错:长文本字段不适合建普通索引(要建也得用全文索引)

D 错:频繁更新的字段建索引会拖慢更新速度

📌 口诀:"主码一定建、查得多的建、改得多的不建、取值少的不建"

练习 1.2 ⭐⭐ 必考 数据类型选择

下列数据类型选择,错误 的是?

📖 查看答案

✅ 错误的是:C

金额、价格、余额等"必须精确"的数值,绝对不能用 FLOAT 或 DOUBLE

原因:浮点数在计算机里是近似存储的,会有精度误差。比如:

0.1 + 0.2 = 0.30000000000000004(不等于 0.3!)

对金额来说,1 分钱的误差日积月累就是大问题。所有金额必须用 DECIMAL(M,N),存的就是精确值。

练习 1.3 ⭐⭐ 中等 CHAR vs VARCHAR

下列字段中,最适合用 CHAR 而不是 VARCHAR 的是?

📖 查看答案

✅ 答案:B

判断口诀:"长度定 → CHAR,长度变 → VARCHAR"

① 学号永远 8 位,长度固定 → 用 CHAR(8)

② 家庭住址、商品名称、详细描述 —— 每条记录长度都不一样,用 VARCHAR 才不浪费空间

类似"长度固定"的字段:身份证号、手机号、邮政编码、银行卡号等

练习 1.4 ⭐⭐ 中等 实施 5 步骤

数据库实施阶段,第一步 应该做什么?

📖 查看答案

✅ 答案:B · 建立数据库结构

实施 5 步顺序:建立结构 → 装入数据 → 编码调试 → 试运行 → 整理文档

逻辑:先有表结构(房子盖好),才能装数据(搬家具),然后写程序连接数据库(接电接水)、试运行(住进去用一段)、最后整理文档。

练习 1.5 ⭐⭐ 中等 运维识别

下列工作 不属于 数据库 DBA 的运维任务?

📖 查看答案

✅ 答案:D

设计 E-R 图属于"概念结构设计"阶段(第 13 章),是项目开始时的工作,不是运维

运维 4 工作:

① 转储和恢复(A 是这个)

② 维护安全性与完整性(B 是这个)

③ 监测并改善性能(C 是这个)

④ 重新组织和构造数据库

口诀:"备恢复、保安全、调性能、重结构"

💻 第二部分 · 数据类型选择实操10 分钟 · 必考

本部分是 实操题。给一组字段,自己选数据类型和约束,再对照标准答案。

练习 2.1 💻 实操 学生表设计

为下面的"学生信息"表选择合适的数据类型和约束:

📋 字段说明
  1. 学号:固定 10 位数字字符串(如 "2024010001")
  2. 姓名:2-10 个汉字
  3. 性别:男 / 女
  4. 出生日期:年月日
  5. 手机号:11 位数字
  6. 身高:精确到小数点后 2 位(如 1.75 米)
  7. 个人简介:可能很长的文字描述

💡 建议:先自己写一遍答案,再点开对照。

📖 查看答案
字段数据类型约束选型理由
学号 CHAR(10) 主码 长度固定 10 位 → CHAR;不能用 INT(开头 0 会丢,且不参与运算)
姓名 VARCHAR(20) 非空 长度变化(2-10 字)→ VARCHAR;utf8mb4 一个汉字最多 4 字节,留富裕
性别 CHAR(2) 或 TINYINT CHAR(2)直接存"男/女";TINYINT用 1/2 表示更省空间
出生日期 DATE 只到日,不需要时间 → DATE 比 DATETIME 省空间
手机号 CHAR(11) ⚠️ 不能用 INT!11 位数字超过 INT 范围
身高 DECIMAL(3,2) 精确小数 → DECIMAL;3 位总长 + 2 位小数(最大 9.99 米够用)
个人简介 TEXT 长文本 → TEXT;如果限制 500 字内可以用 VARCHAR(500)
💡 易错提醒

① 学号、手机号 千万不要用 INT

② 出生日期不要用 VARCHAR 存"2000-01-01"字符串 —— 用 DATE 更标准、能比较大小

③ 身高、价格等精确小数 都用 DECIMAL,不用 FLOAT

练习 2.2 ⭐⭐ 中等 设计改错

某同学设计了一张"订单"表如下,请找出 3 处不合理 的设计并改正:

字段名数据类型说明
order_idINT订单编号(17 位字符)
amountFLOAT订单金额
customer_phoneINT客户手机号(11 位)
order_timeDATETIME下单时间
statusCHAR(10)订单状态(待付款/已发货等)
📖 查看答案

3 处错误:

错误 1:order_id 用 INT

17 位字符的订单编号超过 INT 范围。应改为 CHAR(17)(订单号格式固定)。

错误 2:amount 用 FLOAT

金额必须精确,FLOAT 会有精度误差。应改为 DECIMAL(10,2)

错误 3:customer_phone 用 INT

11 位手机号超出 INT 范围(INT 最大约 21 亿)。应改为 CHAR(11)

💡 status 字段的设计

status 用 CHAR(10) 不算错,但 更好 的做法是用 ENUM 或 TINYINT。

例如:用 TINYINT 存 1/2/3 分别表示"待付款/已发货/已完成",比存中文字符串更省空间、查询更快。

🔍 第三部分 · 索引判断实操10 分钟 · 必考

本部分练习 "哪些字段该建索引"。这是必考点。

练习 3.1 💻 实操 索引判断 · 综合

电商订单系统 有一张订单表,字段如下。对每个字段判断是否建索引,并说明理由:

📋 订单表字段及使用场景
  1. 订单编号:主码
  2. 客户编号:每次查询订单都要按客户筛选;连接客户表时常用
  3. 订单金额:很少作为查询条件(不会按精确金额搜订单)
  4. 订单状态:取值仅 5 个(待付款、已付款、已发货、已签收、已退款);经常更新
  5. 下单时间:经常用于"查最近一周的订单"这种范围查询
  6. 收货地址:很长的文本,几乎不查询
📖 查看答案
字段建?理由
订单编号 ✅ 必建 主码必建唯一索引(DBMS 自动建)
客户编号 ✅ 必建 外键 + 频繁查询/连接 —— 索引收益巨大
订单金额 ❌ 不建 很少作为查询条件,建了浪费
订单状态 ❌ 不建 取值少(区分度低)+ 频繁更新(维护代价高)
下单时间 ✅ 建议建 经常用于范围查询(如"最近一周"),索引有效
收货地址 ❌ 不建 长文本 + 几乎不查 —— 建了没用
💡 总结

这张表 建议建 3 个索引:订单编号(主键自带)、客户编号、下单时间。

这就是真实电商订单表的标准做法 —— 所谓"建索引"不是越多越好,而是 "该建的建,不该建的不建"

练习 3.2 ⭐⭐ 中等 索引利弊分析

下面这种说法 对吗?请说明理由:

"为了让查询都快,应该给所有字段都建上索引。这样无论查什么字段都能用索引加速。"

📖 查看答案

这种说法是错的。原因有 3 个:

问题 1:浪费存储空间

每个索引都是一份"目录",要占额外存储空间。10 个字段就是 10 份索引数据。

问题 2:拖慢增删改

每次 INSERT / UPDATE / DELETE 都要 同时维护所有索引。索引越多,增删改越慢。

对于电商高并发系统,每秒上千次写入,索引太多会直接拖垮数据库。

问题 3:DBMS 选择困难

查询优化器要从多个索引中选最合适的,索引太多反而 增加优化时间

✅ 正确做法:"该建的建,不该建的不建"

① 主码必建

② 频繁出现在 WHERE 中的字段建

③ 连接(JOIN)字段建

④ 频繁更新的、取值少的、几乎不查询的字段不要建

🎯 第四部分 · 综合大题15 分钟 · 必考

本部分是 必考综合大题:给一个关系模式,完成完整的 物理设计 + 写出 CREATE TABLE

综合大题 1 ⭐⭐⭐ 期末重点 完整物理设计

设计一张"图书"表,要求完成 3 步

  1. 设计字段名、数据类型、约束
  2. 写出完整的 CREATE TABLE 语句
  3. 说明应该建哪些索引
📋 关系模式与说明

图书(ISBN, 书名, 作者, 出版社, 出版日期, 价格, 库存量, 简介)

  1. ISBN:固定 13 位(如 "9787121012345")
  2. 书名:1~50 个字,必填
  3. 作者:1~30 个字,必填,经常按作者搜索
  4. 出版社:1~30 个字
  5. 出版日期:年月日
  6. 价格:精确小数,最大不超过 9999.99
  7. 库存量:整数
  8. 简介:可能很长的文字
📖 查看答案

第一步:物理设计表

字段名数据类型约束理由
isbnCHAR(13)主码长度固定 13 位
book_nameVARCHAR(50)非空长度变化
authorVARCHAR(30)非空长度变化
publisherVARCHAR(30)长度变化
publish_dateDATE只要日,不要时间
priceDECIMAL(6,2)精确小数;总位数 6(4 整数 + 2 小数)
stockINT默认 0整数
summaryTEXT长文本

第二步:写出 CREATE TABLE

SQL
CREATE TABLE book (
    isbn          CHAR(13)        NOT NULL COMMENT 'ISBN',
    book_name     VARCHAR(50)     NOT NULL COMMENT '书名',
    author        VARCHAR(30)     NOT NULL COMMENT '作者',
    publisher     VARCHAR(30)              COMMENT '出版社',
    publish_date  DATE                    COMMENT '出版日期',
    price         DECIMAL(6,2)              COMMENT '价格',
    stock         INT           DEFAULT 0 COMMENT '库存量',
    summary       TEXT                    COMMENT '简介',
    PRIMARY KEY (isbn)
);

-- 建索引
CREATE INDEX idx_author ON book(author);

第三步:索引说明

应建索引

isbn(主键自带索引) —— 主码必建

author(手动建) —— 题目说"经常按作者搜索",索引能大幅提速

不建索引

book_name、publisher、price 等字段:题目没说频繁查询,且 book_name 本身查询多用模糊匹配(LIKE '%xxx%'),普通索引帮助有限。

综合大题 2 ⭐⭐⭐ 进阶 含外码的设计

设计一张"借阅记录"表,要求写出完整的 CREATE TABLE 语句(含外键和索引):

📋 关系模式与说明

借阅(借阅编号, 读者编号, ISBN, 借出日期, 应还日期, 实际归还日期)

  1. 借阅编号:自增整数,主码
  2. 读者编号:8 位字符,外键引用 reader 表
  3. ISBN:13 位字符,外键引用 book 表
  4. 借出日期、应还日期:年月日,必填
  5. 实际归还日期:可空(未归还时为 NULL)
  6. 查询场景:经常按"读者编号"查某人的借阅记录;经常按"ISBN"查某本书的借阅历史
📖 查看答案

分析:这道题的关键是 ① 自增主键 ② 外键约束 ③ 给两个外键字段都建索引(因为题目明说"经常按...查")。

SQL
CREATE TABLE borrow (
    borrow_id      INT            AUTO_INCREMENT     COMMENT '借阅编号',
    reader_id      CHAR(8)        NOT NULL            COMMENT '读者编号',
    isbn           CHAR(13)       NOT NULL            COMMENT '图书 ISBN',
    borrow_date    DATE           NOT NULL            COMMENT '借出日期',
    due_date       DATE           NOT NULL            COMMENT '应还日期',
    return_date    DATE                                COMMENT '实际归还日期,未还为 NULL',
    PRIMARY KEY (borrow_id),
    FOREIGN KEY (reader_id) REFERENCES reader(reader_id),
    FOREIGN KEY (isbn) REFERENCES book(isbn)
);

-- 建索引(外键查询频繁,必须建)
CREATE INDEX idx_reader ON borrow(reader_id);
CREATE INDEX idx_isbn   ON borrow(isbn);
💡 关键点

AUTO_INCREMENT 让主键自动 +1,省去手动给编号的麻烦

FOREIGN KEY 加外键约束,保证 reader_id 和 isbn 必须在被引用表中存在

return_date 不加 NOT NULL —— 因为未归还时就是 NULL

④ MySQL 8.0 中 外键字段会自动建索引,但显式建一份更稳妥(兼容旧版本)

📝 复习重点回顾

通过本次练习,你应该已经:

⭐ 期末考点排行榜

按出现频率排序:

  1. 写出 CREATE TABLE 语句:综合大题,分值最高
  2. 数据类型选择题:常考易错(手机号/金额/CHAR vs VARCHAR)
  3. 索引判断题:哪个字段该建索引
  4. 实施 5 步骤、运维 4 工作:填空 / 简答
  5. 数据库设计 6 阶段顺序:填空
💡 三条万能口诀

数据类型:长度定→CHAR,长度变→VARCHAR;金额→DECIMAL;号码→CHAR

索引:主码一定建,查得多的建,改得多的不建,取值少的不建

设计 6 阶段:需 概 逻 物 实 维(需求-概念-逻辑-物理-实施-运维)