乐途乐途
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
  • 学习路径
  • 第1章 数据库基础与安装

    • MySQL 简介
    • MySQL 5.6 到 5.7 到 8.0 关键差异速查
    • 安装 MySQL 5.7
    • 连接与断开服务器
    • 创建数据库
    • 创建数据表
    • 数据库与数据表
    • 加载数据
    • 获取数据库信息
    • 批处理模式
    • SHOW 语句汇总
    • FLUSH 与 RESET 语句
    • my.cnf 核心参数
    • 字符集与排序规则
  • 第2章 SQL基础查询

    • SELECT
    • WHERE
    • ORDER BY
    • LIMIT
    • COUNT
    • 聚合函数
    • 比较运算符
    • 逻辑运算符
    • 算术运算符
    • 模式匹配
    • NULL 值处理
    • UPDATE
    • DELETE
    • REPLACE
    • SELECT INTO
  • 第3章 数据类型与运算符

    • 数值类型
    • 字符串类型
    • 日期时间类型
    • BIT 类型
    • ENUM 类型
    • SET 类型
    • JSON 类型
    • 类型转换
  • 第4章 函数与表达式

    • 字符串函数
    • 数值函数
    • 日期函数
    • 全文检索函数
  • 第5章 高级查询与子查询

    • JOIN
    • 子查询
    • UNION
    • GROUP BY
    • HAVING
    • DISTINCT
  • 第6章 表与索引

    • 数据定义语言
    • 修改表结构
    • 视图
    • 修改视图与检查选项
    • 外键
    • 索引
    • 唯一索引
    • 复合索引
    • 存储引擎对比
    • 分区表
    • 第一范式与第二范式
    • 第三范式与 BC 范式
    • 反范式设计
  • 第7章 存储过程与函数

    • 存储过程
    • 存储函数
    • 变量
    • 流程控制
    • 游标
    • 预处理语句
  • 第8章 事务与锁

    • 事务
    • 事务隔离级别
    • 锁机制
    • MVCC
    • 死锁专题分析
    • LOCK TABLES
    • XA 事务
  • 第9章 用户管理与安全

    • 用户管理
    • 权限管理
    • 角色
    • SQL 注入防范
  • 第10章 性能优化入门

    • 执行计划
    • 索引优化
    • 查询优化
    • 查询优化器提示
    • 慢查询日志
    • InnoDB 深入机制
    • InnoDB 专项优化
    • Performance Schema
    • sys Schema
  • 第11章 复制与高可用

    • 主从复制原理
    • 半同步复制配置
    • binlog 开启与 point-in-time 恢复
    • mysqldump 全库备份
    • mysqldump 单表与条件备份
    • mysqldump 恢复与导入
    • xtrabackup 全量热备
    • xtrabackup 准备与恢复
    • xtrabackup 增量与流式备份
  • 第12章 触发器与事件

    • 触发器
    • 事件调度器
  • 参考

    • MySQL 5.7 专业术语大全
    • MySQL 5.7 关键字与保留字大全

创建数据表

导学

数据库是容器,数据表才是实际存储数据的地方。本节学习 CREATE TABLE 语句的核心语法,理解主键、数据类型和约束的概念,并通过完整示例动手创建多张数据表,观察操作前后的数据状态变化。

定义

CREATE TABLE:DDL 语句,用于在指定数据库中创建一张新表。创建时需要声明列名、数据类型,以及可选的约束条件(如主键、非空、唯一等)。

核心语法

CREATE TABLE [IF NOT EXISTS] 表名 (
    列名1 数据类型 [约束],
    列名2 数据类型 [约束],
    ...
    [表级约束]
) [ENGINE=InnoDB] [DEFAULT CHARSET=utf8mb4];

完整示例一:创建员工信息表

当前数据状态

首先确保有一个测试数据库:

CREATE DATABASE IF NOT EXISTS company
    DEFAULT CHARACTER SET utf8mb4
    DEFAULT COLLATE utf8mb4_unicode_ci;

USE company;

-- 查看当前数据库中的表
SHOW TABLES;

执行结果:

Empty set (0.00 sec)

结果解读:新建的 company 数据库中没有任何表。

操作语句

CREATE TABLE IF NOT EXISTS employees (
    emp_id       INT PRIMARY KEY AUTO_INCREMENT COMMENT '员工ID,主键',
    emp_name     VARCHAR(20) NOT NULL COMMENT '姓名',
    dept         VARCHAR(20) DEFAULT '技术部' COMMENT '部门',
    score        DECIMAL(5,2) COMMENT '绩效分'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
  COMMENT='员工信息表';

操作后的数据状态

SHOW TABLES;
Tables_in_company
employees

查看表结构:

DESC employees;
FieldTypeNullKeyDefaultExtra
emp_idint(11)NOPRINULLauto_increment
emp_namevarchar(20)NONULL
deptvarchar(20)YES技术部
scoredecimal(5,2)YESNULL

查看完整建表语句:

SHOW CREATE TABLE employees\G

结果解读:

定义含义
INT整数类型,范围约 -21亿 到 21亿
AUTO_INCREMENT自增,插入时不指定则自动分配下一个值
NOT NULL该列不允许为 NULL
VARCHAR(20)变长字符串,最多 20 个字符
DEFAULT '技术部'不指定值时的默认值
DECIMAL(5,2)定点数,总共5位,小数点后2位
PRIMARY KEY主键约束,唯一标识每行,自动创建索引
ENGINE=InnoDB使用 InnoDB 存储引擎
COMMENT注释,说明字段或表的业务含义

完整示例二:验证约束效果

当前数据状态

SELECT * FROM employees;

Empty set (0.00 sec)

结果解读:表已创建,但暂无数据。

操作语句:测试 NOT NULL 约束

INSERT INTO employees (emp_name, dept, score) VALUES (NULL, '技术部', 100);

操作后的数据状态:

ERROR 1048 (23000): Column 'emp_name' cannot be null

结果解读:emp_name 列声明了 NOT NULL,插入 NULL 值时被拒绝。

操作语句:测试 DEFAULT 约束

先插入一条合法记录:

INSERT INTO employees (emp_name, score) VALUES ('大翔', 100);

SELECT * FROM employees;
emp_idemp_namedeptscore
1大翔技术部100

再插入一条不指定 dept 的记录:

INSERT INTO employees (emp_name, score) VALUES ('白歌', NULL);

SELECT * FROM employees WHERE emp_id = 2;
emp_idemp_namedeptscore
2白歌技术部NULL

结果解读:未指定 dept 时,自动填充了默认值 技术部。未指定 score 时,填充了 NULL。

操作语句:测试 PRIMARY KEY 唯一性

尝试插入重复的主键:

INSERT INTO employees (emp_id, emp_name, dept, score) VALUES (1, '小崔', '市场部', 80);

操作后的数据状态:

ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'

结果解读:emp_id 是主键,自动具有唯一性约束,重复值被拒绝。

完整示例三:创建带外键的关联表

当前数据状态

SHOW TABLES;
Tables_in_company
employees

结果解读:目前只有 employees 表。接下来创建绩效记录表,演示表之间的关系。

操作语句

-- 创建绩效记录表(含外键)
CREATE TABLE IF NOT EXISTS scores (
    score_id    INT PRIMARY KEY AUTO_INCREMENT COMMENT '记录ID',
    emp_id      INT NOT NULL COMMENT '员工ID',
    score       DECIMAL(5,2) COMMENT '绩效分',
    created_at  TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '记录时间',
    FOREIGN KEY (emp_id) REFERENCES employees(emp_id)
        ON DELETE CASCADE
        ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='绩效记录表';

操作后的数据状态

SHOW TABLES;
Tables_in_company
employees
scores

查看绩效记录表的建表语句:

SHOW CREATE TABLE scores\G

结果解读:

  • FOREIGN KEY 建立了表与表之间的关系
  • ON DELETE CASCADE 表示删除员工时,自动删除其绩效记录
  • ON UPDATE CASCADE 表示员工ID变更时,绩效记录中的 emp_id 同步更新

验证外键约束:

-- employees 表当前有 2 条数据(大翔、白歌)
SELECT * FROM employees;
emp_idemp_namedeptscore
1大翔技术部100
2白歌技术部NULL

尝试插入一条不存在的员工绩效记录:

INSERT INTO scores (emp_id, score) VALUES (999, 85.5);

操作后的数据状态:

ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails

结果解读:外键约束保证了数据的引用完整性。emp_id = 999 在 employees 表中不存在,因此插入被拒绝。

插入合法记录:

INSERT INTO scores (emp_id, score) VALUES (1, 90);

SELECT * FROM scores;
score_idemp_idscorecreated_at
1190.002024-01-15 10:35:00

结果解读:emp_id = 1(大翔)在 employees 表中存在,插入成功。

主键的设计原则

对于 MySQL 5.7 + InnoDB:

  • 推荐使用自增整数(AUTO_INCREMENT)作为主键,InnoDB 的聚簇索引对此做了深度优化
  • 避免使用业务字段(如手机号、身份证号)作为主键,因为业务规则可能变更
  • 避免使用 UUID 作为主键,虽然全局唯一,但随机写入会导致页分裂,性能下降

场景:不同主键策略对比

当前数据状态:

-- 创建自增主键表
CREATE TABLE auto_pk (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    emp_name VARCHAR(20)
) ENGINE=InnoDB;

-- 创建 UUID 主键表
CREATE TABLE uuid_pk (
    id CHAR(36) PRIMARY KEY,
    emp_name VARCHAR(20)
) ENGINE=InnoDB;

操作语句:分别插入数据观察差异。

-- 自增主键:无需指定 id
INSERT INTO auto_pk (emp_name) VALUES ('大翔'), ('白歌');

SELECT * FROM auto_pk;
idemp_name
1大翔
2白歌
-- UUID 主键:必须手动生成
INSERT INTO uuid_pk (id, emp_name) VALUES
('550e8400-e29b-41d4-a716-446655440000', '大翔'),
('550e8400-e29b-41d4-a716-446655440001', '白歌');

SELECT * FROM uuid_pk;
idemp_name
550e8400-e29b-41d4-a716-446655440000大翔
550e8400-e29b-41d4-a716-446655440001白歌

结果解读:

  • 自增主键:自动递增,写入磁盘时数据顺序排列,查询效率高
  • UUID 主键:随机分布,插入时可能导致 InnoDB 页分裂,且占用 36 字节(自增 INT 仅 4 字节)

清理测试表:

DROP TABLE IF EXISTS auto_pk;
DROP TABLE IF EXISTS uuid_pk;

常见误区

误区正解
"每张表都必须有主键"MySQL 5.7 允许没有主键的表,但 InnoDB 会隐式创建 6 字节的隐藏主键。强烈建议显式声明主键。
VARCHAR(255) 越多越好VARCHAR 按需定义,过大的声明会浪费内存(排序缓冲区按声明长度分配)。
TIMESTAMP 和 DATETIME 没区别TIMESTAMP 范围小(1970-2038)、自动转时区、支持自动更新;DATETIME 范围大、不转时区。

验证 TIMESTAMP 和 DATETIME 的区别:

CREATE TABLE time_test (
    id INT PRIMARY KEY AUTO_INCREMENT,
    ts_col TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    dt_col DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;

INSERT INTO time_test (id) VALUES (1);

SELECT * FROM time_test;
idts_coldt_col
12024-01-15 10:40:002024-01-15 10:40:00

结果解读:在 MySQL 5.7 中,两者默认都可以自动填充当前时间。但 TIMESTAMP 会随会话时区转换,而 DATETIME 不会。且 TIMESTAMP 最大只支持到 2038 年。

清理:

DROP TABLE IF EXISTS time_test;

面试考点

Q:为什么 InnoDB 推荐用自增 ID 做主键?

InnoDB 使用聚簇索引,数据按主键顺序存储。自增 ID 是顺序写入,磁盘 I/O 连续,效率高;UUID 或随机 ID 会导致频繁的页分裂和碎片,降低插入和查询性能。

Q:NOT NULL 有什么好处?

  1. 减少 SQL 执行时的 NULL 判断开销;2. 避免聚合函数(如 COUNT)出现意外结果;3. 明确语义,减少程序层的空指针风险。

Q:CHAR 和 VARCHAR 怎么选?

CHAR 定长,适合长度固定的场景(如 MD5 值、性别标志),查询略快;VARCHAR 变长,适合长度差异大的场景(如姓名、地址),节省空间。MySQL 5.7 中 VARCHAR 的存储效率已足够高,绝大多数场景优先用 VARCHAR。

小结

  • CREATE TABLE 需要声明列名、数据类型和约束
  • 主键推荐用 INT/BIGINT UNSIGNED AUTO_INCREMENT
  • 必须显式指定 ENGINE=InnoDB 和 CHARSET=utf8mb4
  • 善用 COMMENT 给字段和表添加注释,这是良好的工程习惯
  • 外键约束保证了数据的引用完整性

清理测试数据库(可选):

-- DROP DATABASE IF EXISTS company;

下一章引子:表创建好了,但里面是空的。接下来学习如何向表中插入数据。

上一页
创建数据库
下一页
数据库与数据表