课程 › 第 14 章 › 实验一
第 14 章 · 实验一 · 在第二节之后

类型、长度与索引

按表 14-1 建供应商表,看长度和 DECIMAL 的范围怎样限制数据,再练习在哪些列上建索引,最后观察 InnoDB 按主码聚簇存放。

环 境

MySQL 8.0 和 MySQL Workbench,机房电脑已装好。所有语句在 Workbench 的 SQL 编辑区中执行。

执 行

Ctrl+Enter 执行光标所在的一句,Ctrl+Shift+Enter 执行全部。Mac 上把 Ctrl 换成 ⌘。

注 意

输入法切到英文。表名、字段名不加引号,字符串值才用单引号。

本次实验的顺序 后一个实验用到前一个的结果

  1. 实验 1-1建立供应商表
  2. 实验 1-2DECIMAL(9,2) 的范围
  3. 实验 1-3主码上已有索引
  4. 实验 1-4为查询条件建索引
  5. 实验 1-5唯一索引
  6. 实验 1-6按主码聚簇
第一步

数据准备(必做)

新建一个空的 ecommerce 库。本次实验建的是练习用的表,实验二会重新建库。

整段复制,全部执行下载 .sql
-- 第 14 章实验一数据:新建一个空的 ecommerce 库
-- 整段执行一次即可,想从头再做时重新执行。
DROP DATABASE IF EXISTS ecommerce;
CREATE DATABASE ecommerce DEFAULT CHARACTER SET utf8mb4;
USE ecommerce;
1-1

建立供应商表

讲义 · 存储记录结构与聚簇
目的
建立供应商表 Supplier,编号定长 5 位,名称和邮箱变长,每个字段写上说明,再插入一个编号超长的供应商。
前提
已执行数据准备,当前库是 ecommerce。
  1. 建立 Supplier,字段为 supid、supname、email、telephone,每个字段加 COMMENT
  2. 插入一个编号为 5 位的供应商
  3. 插入一个编号为 6 位的供应商

参考答案

可以直接复制到 Workbench 执行
CREATE TABLE Supplier (
  supid CHAR(5) NOT NULL COMMENT '供应商编号',
  supname VARCHAR(40) NOT NULL COMMENT '供应商名称',
  email VARCHAR(40) COMMENT '电子邮箱',
  telephone CHAR(11) COMMENT '联系方式',
  PRIMARY KEY (supid)
);
INSERT INTO Supplier VALUES ('01001', '华信图书公司', 'hx@163.com', '18600008965');
-- 编号多了一位,报错 1406
INSERT INTO Supplier VALUES ('010002', '东方数码公司', NULL, '13900001234');

语句解释

CHAR(5)定长 5 个字符。前 2 位表示省,后 3 位是序号,一个省最多 1000 家
VARCHAR(40)变长,名称长短不一,按实际长度存放
COMMENT字段的说明,SHOW CREATE TABLE 时能看到
报错 1406Data too long,值超过了字段的长度
执行后看:第一条插入成功,第二条报错 1406。长度定得太短,将来的数据就放不进去。
1-2

DECIMAL(9,2) 的范围

讲义 · 供应表、分类表与订单表
目的
案例中的单价都用 DECIMAL(9,2),验证这个类型能存放的最大值是 9999999.99。
前提
已完成实验 1-1。
  1. 建立只有一个 DECIMAL(9,2) 字段的表
  2. 插入最大值和一个三位小数
  3. 插入 10000000

参考答案

可以直接复制到 Workbench 执行
CREATE TABLE price_test (price DECIMAL(9,2));
INSERT INTO price_test VALUES (9999999.99);
-- 小数超过 2 位,四舍五入
INSERT INTO price_test VALUES (12.345);
SELECT * FROM price_test;
-- 超出范围,报错 1264
INSERT INTO price_test VALUES (10000000);

语句解释

DECIMAL(9,2)一共 9 位数字,其中 2 位小数,整数部分最多 7 位
12.345按 2 位小数四舍五入为 12.35
报错 1264Out of range,超出了类型能表示的范围
金额用 DECIMAL按十进制精确存放,不像 FLOAT 那样有误差
执行后看:查询得到 9999999.99 和 12.35。插入 10000000 报错 1264。
1-3

主码上已有索引

讲义 · 在哪些列上建立索引
目的
查看供应商表的索引,看主码上是否已经有索引,再在主码上建一个普通索引,看看结果。
前提
已完成实验 1-2。
  1. 查看 Supplier 的索引
  2. 在 supid 上建索引 Supplier_supid,再查看
  3. 删除这个多余的索引

参考答案

可以直接复制到 Workbench 执行
SHOW INDEX FROM Supplier;
-- 在主码上再建一个普通索引
CREATE INDEX Supplier_supid ON Supplier (supid);
SHOW INDEX FROM Supplier;
-- 与主码的索引重复,删掉
DROP INDEX Supplier_supid ON Supplier;

语句解释

PRIMARY定义主码时,MySQL 自动在主码上建立唯一索引
Supplier_supid同一列上的第二个索引,查询用不上,还要占空间、在修改时维护
DROP INDEX删除索引
执行后看:一开始只有 PRIMARY 一个索引。建完后 supid 上有两个索引,MySQL 不报错,但第二个是多余的。
1-4

为查询条件建索引

讲义 · 在哪些列上建立索引
目的
经常按供应商名称查询时,在 supname 上建索引,用 EXPLAIN 比较建索引前后的执行方式。
前提
已完成实验 1-3。
  1. 再插入两个供应商
  2. 用 EXPLAIN 查看按名称查询的执行方式
  3. 在 supname 上建索引,再看一次

参考答案

可以直接复制到 Workbench 执行
INSERT INTO Supplier VALUES
('01002', '东方数码公司', 'df@163.com', '13900001234'),
('02001', '远达文具公司', 'yd@163.com', '13600007788');
EXPLAIN SELECT * FROM Supplier WHERE supname = '东方数码公司';
CREATE INDEX idx_supname ON Supplier (supname);
EXPLAIN SELECT * FROM Supplier WHERE supname = '东方数码公司';

语句解释

EXPLAIN显示 MySQL 打算怎样执行这条查询,并不真的执行
type 为 ALL逐行扫描全表
type 为 ref,key 为 idx_supname通过索引直接找到符合条件的行
什么时候建经常作为查询条件、取值较多、不经常修改的列
执行后看:第一次 type 为 ALL,key 为空。建索引后 type 为 ref,key 为 idx_supname。
1-5

唯一索引

讲义 · 在哪些列上建立索引
目的
要求供应商的邮箱不能重复,在 email 上建唯一索引,再插入一个邮箱重复的供应商。
前提
已完成实验 1-4。
  1. 在 email 上建唯一索引
  2. 插入一个邮箱与华信图书公司相同的供应商

参考答案

可以直接复制到 Workbench 执行
CREATE UNIQUE INDEX idx_email ON Supplier (email);
-- 邮箱与华信图书公司相同,报错 1062
INSERT INTO Supplier VALUES ('02002', '星河电器公司', 'hx@163.com', '13700005678');

语句解释

UNIQUE INDEX唯一索引,既能加快查询,又保证这一列的值不重复
报错 1062Duplicate entry,值已经存在
空值唯一索引允许有多个空值
执行后看:报错 1062,星河电器公司没有插入。
1-6

按主码聚簇

讲义 · 存储记录结构与聚簇
目的
打乱顺序插入几行,不加 ORDER BY 查询,观察 InnoDB 按主码顺序存放数据。
前提
已完成实验 1-5。
  1. 建立一张以 id 为主码的表
  2. 按 30、10、20 的顺序插入
  3. 查询全部数据

参考答案

可以直接复制到 Workbench 执行
CREATE TABLE cluster_test (
  id INT NOT NULL,
  name VARCHAR(10),
  PRIMARY KEY (id)
);
-- 故意打乱顺序插入
INSERT INTO cluster_test VALUES (30, 'c'), (10, 'a'), (20, 'b');
SELECT * FROM cluster_test;

语句解释

聚簇把码值相近的记录存放在一起。InnoDB 的表按主码聚簇存放,主码索引就是聚簇索引
查询结果全表扫描时按聚簇索引的顺序读出
ORDER BY要保证结果的顺序,仍然要写 ORDER BY
执行后看:结果按 10、20、30 的顺序排列,与插入的顺序无关。
保山学院·人工智能教研室·曹鼎鼎