【MySQL】建库就是建目录?字符集校验规则、备份恢复与alter改表实操

3.MySQL操作库

文章目录

上一篇笔记把数据库从概念讲到了落地:建库就是在 /var/lib/mysql 下建目录、建表就是在目录里建文件;SQL 分 DDL、DML、DCL 三类;MySQL 是分层网络服务,默认存储引擎是 InnoDB。上篇止于"认识",本篇进入"上手"。

实操分两大阶段:先做库的操作------创建、查看、修改、删除数据库,重点讲字符集与校验规则,最后讲备份恢复;再做表的操作------创建表、查看表结构、修改表、删除表,并借建表比较 MyISAM 与 InnoDB 在磁盘文件上的差异。老师始终把库表操作与 Linux 文件操作对照讲解,本篇沿用这条线:每类 SQL 都回答它落到 Linux 上到底做了什么。

一、建库与删库:一条 SQL 对应一个目录

库的操作从建库开始。创建数据库的 SQL 非常简单,完整语法如下(中括号表示可选项):

sql 复制代码
CREATE DATABASE [IF NOT EXISTS] db_name
    [DEFAULT] CHARACTER SET charset_name   -- 字符集
    [DEFAULT] COLLATE collation_name       -- 校验规则

语法上只需记三点:

  1. 关键字大小写均可,习惯大写只为可读性
  2. 中括号内是可选项:字符集、校验规则子句不写则采用系统默认。
  3. create database 的 database 不带 s,而查看命令 show databases 带 s,固定用法不要混。库名结合业务自行定义。

亲手验证建库与 Linux 的对应。数据目录是 /var/lib/mysql(需超级用户权限),打开 mysql 客户端执行:

sql 复制代码
show databases;       -- 查看当前可见的数据库列表
create database db1;  -- 建库
drop database db1;    -- 删库

每执行一次建库或删库,回到数据目录 ls,同名目录随之出现或消失。建库的本质是在数据目录下创建一个同名目录;删库的本质是连同目录递归删除。库目录里只有 db.opt 等少量配置文件,内容要在建表之后才充实起来。四条 SQL 与 Linux 操作的对应关系:
#mermaid-svg-Yk99MRjbNi94YG5R{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Yk99MRjbNi94YG5R .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Yk99MRjbNi94YG5R .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Yk99MRjbNi94YG5R .error-icon{fill:#552222;}#mermaid-svg-Yk99MRjbNi94YG5R .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Yk99MRjbNi94YG5R .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Yk99MRjbNi94YG5R .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Yk99MRjbNi94YG5R .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Yk99MRjbNi94YG5R .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Yk99MRjbNi94YG5R .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Yk99MRjbNi94YG5R .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Yk99MRjbNi94YG5R .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Yk99MRjbNi94YG5R .marker.cross{stroke:#333333;}#mermaid-svg-Yk99MRjbNi94YG5R svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Yk99MRjbNi94YG5R p{margin:0;}#mermaid-svg-Yk99MRjbNi94YG5R .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Yk99MRjbNi94YG5R .cluster-label text{fill:#333;}#mermaid-svg-Yk99MRjbNi94YG5R .cluster-label span{color:#333;}#mermaid-svg-Yk99MRjbNi94YG5R .cluster-label span p{background-color:transparent;}#mermaid-svg-Yk99MRjbNi94YG5R .label text,#mermaid-svg-Yk99MRjbNi94YG5R span{fill:#333;color:#333;}#mermaid-svg-Yk99MRjbNi94YG5R .node rect,#mermaid-svg-Yk99MRjbNi94YG5R .node circle,#mermaid-svg-Yk99MRjbNi94YG5R .node ellipse,#mermaid-svg-Yk99MRjbNi94YG5R .node polygon,#mermaid-svg-Yk99MRjbNi94YG5R .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Yk99MRjbNi94YG5R .rough-node .label text,#mermaid-svg-Yk99MRjbNi94YG5R .node .label text,#mermaid-svg-Yk99MRjbNi94YG5R .image-shape .label,#mermaid-svg-Yk99MRjbNi94YG5R .icon-shape .label{text-anchor:middle;}#mermaid-svg-Yk99MRjbNi94YG5R .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Yk99MRjbNi94YG5R .rough-node .label,#mermaid-svg-Yk99MRjbNi94YG5R .node .label,#mermaid-svg-Yk99MRjbNi94YG5R .image-shape .label,#mermaid-svg-Yk99MRjbNi94YG5R .icon-shape .label{text-align:center;}#mermaid-svg-Yk99MRjbNi94YG5R .node.clickable{cursor:pointer;}#mermaid-svg-Yk99MRjbNi94YG5R .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Yk99MRjbNi94YG5R .arrowheadPath{fill:#333333;}#mermaid-svg-Yk99MRjbNi94YG5R .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Yk99MRjbNi94YG5R .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Yk99MRjbNi94YG5R .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Yk99MRjbNi94YG5R .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Yk99MRjbNi94YG5R .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Yk99MRjbNi94YG5R .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Yk99MRjbNi94YG5R .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Yk99MRjbNi94YG5R .cluster text{fill:#333;}#mermaid-svg-Yk99MRjbNi94YG5R .cluster span{color:#333;}#mermaid-svg-Yk99MRjbNi94YG5R div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Yk99MRjbNi94YG5R .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Yk99MRjbNi94YG5R rect.text{fill:none;stroke-width:0;}#mermaid-svg-Yk99MRjbNi94YG5R .icon-shape,#mermaid-svg-Yk99MRjbNi94YG5R .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Yk99MRjbNi94YG5R .icon-shape p,#mermaid-svg-Yk99MRjbNi94YG5R .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Yk99MRjbNi94YG5R .icon-shape .label rect,#mermaid-svg-Yk99MRjbNi94YG5R .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Yk99MRjbNi94YG5R .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Yk99MRjbNi94YG5R .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Yk99MRjbNi94YG5R :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 对应
对应
对应
对应
create database db1
数据目录下创建 db1 目录
drop database db1
递归删除 db1 目录
show databases
列出数据目录下的目录
use db1
cd 进入 db1 目录

三点补充认识:

  1. 目录与库双向联动 。手动 mkdir 一个目录,show databases 同样能列出它;rm 掉这个目录它随之消失。这反向印证了"库即目录",但建库必须走 SQL,禁止手动 mkdir,手动创建的目录缺少数据库应有的元信息与结构。
  2. if not exists 用于防重。不带该选项时重复创建同名库会直接报错;加上后库已存在则跳过创建、仅给提示,不中断执行,适合初始化脚本反复运行。
  3. 删库不可逆:目录一删,将来库内所有的表与数据一并消失。先备份再删除,备份方法见第七节。

二、字符集与校验规则:存与比必须同编码

建库前先搞懂一对最容易混淆的概念:

  1. 字符集(character set)决定数据以什么编码存储。同一段文字按 utf8 还是 gbk 编码,落盘的字节完全不同。
  2. 校验规则(collation)决定比较与排序时按什么规则解读数据。查询 name = 'a'、按 name 排序,都要把数据逐字节比对,按哪套规则比、是否区分大小写,由校验规则决定。

两者在绝大多数的情况下是一致的:存进去用一套编码,取出来比较用另一套,有可能乱码或比较失真 。但并不是说必须一致,"怎么存"和"怎么比"是两个独立的问题 ,编码定下来后,比较规则并没有被定死 。同样是 utf8 编码的字节,可以有 utf8_general_ci(不区分大小写、宽松)、utf8_bin(逐字节比)、utf8_unicode_ci(按 Unicode 算法更精确地排)......一个字符集天然对应多种校验规则。

先看当前系统与库的默认值:

sql 复制代码
show variables like 'character_set_database';   -- 当前默认字符集
show variables like 'collation_database';       -- 当前默认校验规则

查看系统支持的全部字符集与校验规则:

sql 复制代码
show charset;     -- 全部字符集(utf8 支持中文)
show collation;   -- 全部校验规则

show collation 的结果里,校验规则与字符集存在配套关系,例如 gbk 配套的默认校验规则是 gbk_chinese_ci;字符集选定后,配套校验规则随之确定。

三、建库时显式指定编码:就近原则

默认值够用,但建库语句支持显式指定,写法等价、效果相同:

sql 复制代码
create database db2 charset=utf8;                              -- 写法一:charset 等号
create database db3 character set utf8 collate utf8_general_ci;  -- 写法二:character set 空格
create database db4 charset=gbk collate gbk_chinese_ci;        -- 中文库可选 gbk

建好的库在目录内会多出一个 db.opt 文件,里面记录的正是该库的字符集与校验规则;指定为 gbk 的库,db.opt 里就是 gbk 与 gbk_chinese_ci。

由此引出就近原则:建库 SQL 里显式写了编码,按写的执行;没写,按系统默认执行。默认值沿"mysqld 配置、库、表"逐级下传:
#mermaid-svg-TaHgn2Ac8VBSDFiK{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-TaHgn2Ac8VBSDFiK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-TaHgn2Ac8VBSDFiK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-TaHgn2Ac8VBSDFiK .error-icon{fill:#552222;}#mermaid-svg-TaHgn2Ac8VBSDFiK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-TaHgn2Ac8VBSDFiK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-TaHgn2Ac8VBSDFiK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-TaHgn2Ac8VBSDFiK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-TaHgn2Ac8VBSDFiK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-TaHgn2Ac8VBSDFiK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-TaHgn2Ac8VBSDFiK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-TaHgn2Ac8VBSDFiK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-TaHgn2Ac8VBSDFiK .marker.cross{stroke:#333333;}#mermaid-svg-TaHgn2Ac8VBSDFiK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-TaHgn2Ac8VBSDFiK p{margin:0;}#mermaid-svg-TaHgn2Ac8VBSDFiK .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-TaHgn2Ac8VBSDFiK .cluster-label text{fill:#333;}#mermaid-svg-TaHgn2Ac8VBSDFiK .cluster-label span{color:#333;}#mermaid-svg-TaHgn2Ac8VBSDFiK .cluster-label span p{background-color:transparent;}#mermaid-svg-TaHgn2Ac8VBSDFiK .label text,#mermaid-svg-TaHgn2Ac8VBSDFiK span{fill:#333;color:#333;}#mermaid-svg-TaHgn2Ac8VBSDFiK .node rect,#mermaid-svg-TaHgn2Ac8VBSDFiK .node circle,#mermaid-svg-TaHgn2Ac8VBSDFiK .node ellipse,#mermaid-svg-TaHgn2Ac8VBSDFiK .node polygon,#mermaid-svg-TaHgn2Ac8VBSDFiK .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-TaHgn2Ac8VBSDFiK .rough-node .label text,#mermaid-svg-TaHgn2Ac8VBSDFiK .node .label text,#mermaid-svg-TaHgn2Ac8VBSDFiK .image-shape .label,#mermaid-svg-TaHgn2Ac8VBSDFiK .icon-shape .label{text-anchor:middle;}#mermaid-svg-TaHgn2Ac8VBSDFiK .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-TaHgn2Ac8VBSDFiK .rough-node .label,#mermaid-svg-TaHgn2Ac8VBSDFiK .node .label,#mermaid-svg-TaHgn2Ac8VBSDFiK .image-shape .label,#mermaid-svg-TaHgn2Ac8VBSDFiK .icon-shape .label{text-align:center;}#mermaid-svg-TaHgn2Ac8VBSDFiK .node.clickable{cursor:pointer;}#mermaid-svg-TaHgn2Ac8VBSDFiK .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-TaHgn2Ac8VBSDFiK .arrowheadPath{fill:#333333;}#mermaid-svg-TaHgn2Ac8VBSDFiK .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-TaHgn2Ac8VBSDFiK .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-TaHgn2Ac8VBSDFiK .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TaHgn2Ac8VBSDFiK .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-TaHgn2Ac8VBSDFiK .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TaHgn2Ac8VBSDFiK .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-TaHgn2Ac8VBSDFiK .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-TaHgn2Ac8VBSDFiK .cluster text{fill:#333;}#mermaid-svg-TaHgn2Ac8VBSDFiK .cluster span{color:#333;}#mermaid-svg-TaHgn2Ac8VBSDFiK div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-TaHgn2Ac8VBSDFiK .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-TaHgn2Ac8VBSDFiK rect.text{fill:none;stroke-width:0;}#mermaid-svg-TaHgn2Ac8VBSDFiK .icon-shape,#mermaid-svg-TaHgn2Ac8VBSDFiK .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TaHgn2Ac8VBSDFiK .icon-shape p,#mermaid-svg-TaHgn2Ac8VBSDFiK .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-TaHgn2Ac8VBSDFiK .icon-shape .label rect,#mermaid-svg-TaHgn2Ac8VBSDFiK .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TaHgn2Ac8VBSDFiK .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-TaHgn2Ac8VBSDFiK .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-TaHgn2Ac8VBSDFiK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 建库未指定则继承
建表未指定则继承
就近原则:以写的为准
就近原则:以写的为准
mysqld 配置默认

utf8 / utf8_general_ci
库(db.opt 记录)

建库 SQL 显式 charset / collate
建表 SQL 显式 charset / collate / engine

为什么源头已配好 utf8,每一层还要保留"指定编码"的能力?因为表默认继承所在库的编码:一个库里可能有各种业务表,个别场景需要差异化(如对接遗留系统的 gbk 数据)时在库层指定即可。绝大多数场景建库不必手写编码,默认 utf8 即满足要求。

四、校验规则影响查询与排序

字符集不同影响的是可读性(乱码),而校验规则不同会改变查询与排序的语义,用实验验证。建两个库,字符集相同(默认 utf8),只把校验规则分开:

sql 复制代码
create database test1 collate utf8_general_ci;   -- 不区分大小写
create database test2 collate utf8_bin;          -- 区分大小写(按二进制逐字节比较)

collate 与 charset 可以只写其一:只指定 collate 时,字符集仍取默认 utf8。往两个库里放完全相同的表和数据:

sql 复制代码
use test1;
create table person (name varchar(20));
insert into person values ('a'), ('A'), ('b'), ('B');

test2 重复同样的三条语句。执行等值查询 name = 'a':

txt 复制代码
-- test1:utf8_general_ci
mysql> select * from person where name='a';
| a |
| A |    -- 小写 a 与大写 A 都被查出:不区分大小写

-- test2:utf8_bin
mysql> select * from person where name='a';
| a |    -- 只返回小写 a:严格区分大小写

再看排序,执行 select * from person order by name(默认升序):

txt 复制代码
-- test1:utf8_general_ci   结果 a、A、b、B   忽略大小写,字母按组排
-- test2:utf8_bin          结果 A、B、a、b   大写 ASCII 码小于小写,按二进制排

结论:字段的等值比较与排序行为都由校验规则决定

五、查看库:show databases、show create database、use

查看层面有两条命令:show databases 看库的清单,show create database 看某个库当初是怎么建的:

sql 复制代码
show databases;               -- 当前用户可见的数据库列表
show create database test2;   -- 显示建库语句(含字符集与校验规则)

show create database 的输出形如课件中的 mytest 示例(省略了表格边框):

txt 复制代码
mysql> show create database mytest;
CREATE DATABASE `mytest` /*!40100 DEFAULT CHARACTER SET utf8 */

输出与当初敲的语句可能不完全相同,三点细节:

  1. 库名被自动包上反引号:防止库名恰好是 MySQL 关键字或含特殊字符时产生歧义。
  2. /*!40100 ... */ 不是注释,是版本条件判断:MySQL 版本大于等于 4.01(40100 即版本号)才执行括号内的语句,这是建库语句跨版本兼容的机制。
  3. 语句已被服务端规范化:统一大小写、补齐默认值,呈现为标准格式。

库在 Linux 上是一个目录,使用前要先进去:

sql 复制代码
use test1;          -- 选择数据库(对应 cd 进入目录)
select database();  -- 查看当前所在库;未选择库时返回 NULL

select database() 是一行函数查询,脚本里常用它确认当前上下文,避免把表建进错误的库。

六、修改库与删除库

库层面允许的修改很有限,几乎只改编码

sql 复制代码
alter database test2 charset=gbk;   -- 修改字符集

执行后 test2 目录内 db.opt 的字符集变为 gbk;只改字符集不写 collate 时,MySQL 会自动配上该字符集默认的校验规则(gbk 配 gbk_chinese_ci)。show create database test2 可确认改动生效。

删除库:

sql 复制代码
drop database [if exists] test2;   -- if exists:存在才删,防止误报错

drop database 是级联删除:目录连同其中所有表与数据一并消失,没有回收站。围绕删与改有两点纪律、一条禁令:

  1. 库轻易不删。确需删除先做备份(第七节),并确认没有上层应用正在使用。
  2. 库名轻易不改,MySQL 不支持重命名库 。早期版本曾短暂支持 rename database(5.1.7 引入、5.1.23 移除),后因官方认定该语句可能导致库内容丢失而被移除;直接 mv 数据目录改名同样不被推荐。原因很实际:上层应用代码里写死了库名,库名一变,所有依赖它的程序全部失联,改库名约等于删库重建。
  3. 因业务需要"换名",正道是走备份恢复。

七、备份与恢复:mysqldump 与 source

先回答"为什么不直接拷贝目录"。直接拷贝或打包数据目录、mv 改名都不被推荐:数据库文件与版本强相关(低版本建出的文件高版本未必识别),绕过服务端直接操作目录风险高,库名又不可改(上一节)。官方做法是用 MySQL 自带的 mysqldump 做逻辑备份。

以 test1 库为例(内含第四节实验的 person 表),退出 mysql,在 shell 下执行:

bash 复制代码
mysqldump -P3306 -u root -p -B test1 > test1.sql

选项含义:-P3306 指定端口(默认即 3306),-u root 指定用户,-p 回车后输入密码(本机免密直接回车),-B test1 指明备份整个库,> 是 shell 重定向,把输出写进文件(见 基础 IO 的重定向)。打开生成的 test1.sql,能看到一连串熟悉的语句(节选,头部版本注释已省略):

sql 复制代码
CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test1` /*!40100 DEFAULT CHARACTER SET utf8 */;  -- 带 -B 时才有建库语句
USE `test1`;

DROP TABLE IF EXISTS `person`;                   -- 先删后建,文件可重复执行
CREATE TABLE `person` (
  `name` varchar(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `person` VALUES ('a'),('A'),('b'),('B');  -- 数据逐条补回

带 -B 时先有 create database test1,随后 drop table 再 create table 重建 person,最后逐条 insert 补回数据 。所以 mysqldump 备份的不是某个数据文件的快照,而是该库自建库以来的全部有效 SQL 历史;备份文件是纯文本,可阅读、可传输。

恢复在 mysql 客户端内用 source 执行文件里的 SQL:

sql 复制代码
source /path/to/test1.sql;   -- 逐条执行文件内 SQL,路径按实际填写

执行完 show databases 可见 test1 回来,use test1、show tables、select * from person,数据原样恢复。备份恢复的典型场景是迁移或定期同步到另一台机器:
#mermaid-svg-ibZbli0zaXbOMg9R{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ibZbli0zaXbOMg9R .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ibZbli0zaXbOMg9R .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ibZbli0zaXbOMg9R .error-icon{fill:#552222;}#mermaid-svg-ibZbli0zaXbOMg9R .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ibZbli0zaXbOMg9R .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ibZbli0zaXbOMg9R .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ibZbli0zaXbOMg9R .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ibZbli0zaXbOMg9R .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ibZbli0zaXbOMg9R .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ibZbli0zaXbOMg9R .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ibZbli0zaXbOMg9R .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ibZbli0zaXbOMg9R .marker.cross{stroke:#333333;}#mermaid-svg-ibZbli0zaXbOMg9R svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ibZbli0zaXbOMg9R p{margin:0;}#mermaid-svg-ibZbli0zaXbOMg9R .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ibZbli0zaXbOMg9R .cluster-label text{fill:#333;}#mermaid-svg-ibZbli0zaXbOMg9R .cluster-label span{color:#333;}#mermaid-svg-ibZbli0zaXbOMg9R .cluster-label span p{background-color:transparent;}#mermaid-svg-ibZbli0zaXbOMg9R .label text,#mermaid-svg-ibZbli0zaXbOMg9R span{fill:#333;color:#333;}#mermaid-svg-ibZbli0zaXbOMg9R .node rect,#mermaid-svg-ibZbli0zaXbOMg9R .node circle,#mermaid-svg-ibZbli0zaXbOMg9R .node ellipse,#mermaid-svg-ibZbli0zaXbOMg9R .node polygon,#mermaid-svg-ibZbli0zaXbOMg9R .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ibZbli0zaXbOMg9R .rough-node .label text,#mermaid-svg-ibZbli0zaXbOMg9R .node .label text,#mermaid-svg-ibZbli0zaXbOMg9R .image-shape .label,#mermaid-svg-ibZbli0zaXbOMg9R .icon-shape .label{text-anchor:middle;}#mermaid-svg-ibZbli0zaXbOMg9R .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ibZbli0zaXbOMg9R .rough-node .label,#mermaid-svg-ibZbli0zaXbOMg9R .node .label,#mermaid-svg-ibZbli0zaXbOMg9R .image-shape .label,#mermaid-svg-ibZbli0zaXbOMg9R .icon-shape .label{text-align:center;}#mermaid-svg-ibZbli0zaXbOMg9R .node.clickable{cursor:pointer;}#mermaid-svg-ibZbli0zaXbOMg9R .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ibZbli0zaXbOMg9R .arrowheadPath{fill:#333333;}#mermaid-svg-ibZbli0zaXbOMg9R .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ibZbli0zaXbOMg9R .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ibZbli0zaXbOMg9R .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ibZbli0zaXbOMg9R .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ibZbli0zaXbOMg9R .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ibZbli0zaXbOMg9R .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ibZbli0zaXbOMg9R .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ibZbli0zaXbOMg9R .cluster text{fill:#333;}#mermaid-svg-ibZbli0zaXbOMg9R .cluster span{color:#333;}#mermaid-svg-ibZbli0zaXbOMg9R div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ibZbli0zaXbOMg9R .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ibZbli0zaXbOMg9R rect.text{fill:none;stroke-width:0;}#mermaid-svg-ibZbli0zaXbOMg9R .icon-shape,#mermaid-svg-ibZbli0zaXbOMg9R .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ibZbli0zaXbOMg9R .icon-shape p,#mermaid-svg-ibZbli0zaXbOMg9R .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ibZbli0zaXbOMg9R .icon-shape .label rect,#mermaid-svg-ibZbli0zaXbOMg9R .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ibZbli0zaXbOMg9R .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ibZbli0zaXbOMg9R .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ibZbli0zaXbOMg9R :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 拷贝到机器 B
机器 A

mysqldump -B test1 > test1.sql
test1.sql

库的完整 SQL 历史
机器 B

source test1.sql
test1 库与数据原样恢复

变体语法按需取用:

bash 复制代码
mysqldump -u root -p 库名 表1 表2 > 文件.sql    # 只备份库中的若干表(不带 -B)
mysqldump -u root -p -B 库1 库2 > 文件.sql      # 同时备份多个库

-B 是关键开关:带 -B,备份文件含 create database,恢复时无需预建库;不带 -B(如只备份若干表),文件里没有建库语句,恢复前必须先把库手动建好、use 进入,再 source。上一节说的"换名恢复"正是利用这一点:不带 -B 备份旧库内容,建好新名空库,source 回去。

八、show processlist:查看谁连在库上

库操作部分最后给一个运维小命令。感觉数据库访问变慢时,先看当前有哪些连接:

sql 复制代码
show processlist;

结果示例(行已精简):

txt 复制代码
+----+------+-----------+------+---------+------+-------+-------------------+
| Id | User | Host      | db   | Command | Time | State | Info              |
+----+------+-----------+------+---------+------+-------+-------------------+
| 2  | root | localhost | test | Sleep   | 1386 |       | NULL              |
| 3  | root | localhost | NULL | Query   | 0    | NULL  | show processlist  |
+----+------+-----------+------+---------+------+-------+-------------------+

各列含义:Id 连接编号,User 登录用户,Host 来源主机,db 正在使用的库(NULL 表示未选库),Command 当前状态(Sleep 空闲挂起、Query 正在执行查询),Time 已持续秒数,Info 正在执行的语句。用途有二:排查慢与排查入侵。发现陌生来源的连接(尤其 Host 不是本机的),很可能库已被入侵;库变慢时看谁在跑什么 SQL,空闲挂起过久的连接是清理对象。

库的操作至此收束为一条纪律:库建好后轻易不动,改名、删库都要先备份并评估上层影响。下面进入本课第二阶段:库内部的表。

九、建表:语法与完整示例

第二阶段处理库里面的表,同样是四个话题:创建表、查看表、修改表、删除表,即表结构的增删查改。先建表。建表语法与建库对称,区别在于多了圆括号内的列定义:

sql 复制代码
CREATE TABLE [IF NOT EXISTS] table_name (
    field1 datatype [comment '列说明'],
    field2 datatype [comment '列说明']
) character set 字符集 collate 校验规则 engine 存储引擎;

语法要点:

  1. 列定义成对出现:列名在前、类型在后。comment '说明' 给列加注释,团队协作时通过 show create table 回看。
  2. 列之间用逗号分隔,最后一列后面不能有逗号,否则语法错误。
  3. 圆括号后的 character set、collate、engine 子句都可省略:省略时表继承所在库的字符集与校验规则,存储引擎取配置默认 InnoDB
  4. 列类型(int、varchar、date 等)本课先用起来,取值规则由下一课《4.MySQL数据类型》专门展开。

课程演示建两张结构完全相同的表,故意把存储引擎分开(引擎与编码一样,等号、空格两种风格等价):

sql 复制代码
create database user_db charset=utf8;   -- 建演示库
use user_db;

create table users (                    -- 写法一:空格风格,MyISAM 引擎
    id int,
    name varchar(20) comment '用户名',
    password char(32) comment '密码是 32 位的 md5 值',
    birthday date comment '生日'
) character set utf8 collate utf8_general_ci engine MyISAM;

create table users2 (                   -- 写法二:等号风格,InnoDB 引擎
    id int,
    name varchar(20) comment '用户名',
    password char(32) comment '密码是 32 位的 md5 值',
    birthday date comment '生日'
) charset=utf8 collate=utf8_general_ci engine=InnoDB;

回车后 user_db 目录内立即多出两张表对应的磁盘文件。为什么建两张一样的表?下一节看存储引擎如何改变文件形态。

十、存储引擎不同,磁盘文件不同

回到数据目录观察两张表的文件:

txt 复制代码
$ ls /var/lib/mysql/user_db
db.opt   users.frm   users.MYD   users.MYI    -- users:3 个文件
         users2.frm  users2.ibd               -- users2:2 个文件

同为一条 create table,文件个数不同,分工如下:

引擎 文件数 文件分工
MyISAM 3 表结构 .frm;数据文件 .MYD;索引文件 .MYI,数据与索引分离
InnoDB(默认) 2 表结构 .frm;.ibd 内数据与索引合并存放

结论:存储引擎决定表在磁盘上的组织方式,文件个数与分工随引擎不同而不同。这正是《2.MySQL数据库基础》所说"存储引擎是存储方案的具体实现"的落地证据;《12.MySQL索引(上)》讲磁盘 IO 时见到的 .ibd,就是 InnoDB 表的数据文件。文件内部是二进制格式,由 mysqld 服务端维护,使用者无需直接操作。列类型、字符集、引擎共同构成表的完整定义,show create table 可以看到全部细节(下一节)。

十一、查看表结构

建好的表如何查看?三个命令各管一层:

sql 复制代码
show tables;                  -- 当前库有哪些表
desc users;                   -- 表内字段明细(desc 是 describe 的缩写)
show create table users\G;    -- 建表原语完整回放(\G 让输出竖排,更易读)

desc users 输出形如:

txt 复制代码
mysql> desc users;
+----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| id       | int(11)     | YES  |     | NULL    |       |
| name     | varchar(20) | YES  |     | NULL    |       |
| password | char(32)    | YES  |     | NULL    |       |
| birthday | date        | YES  |     | NULL    |       |
+----------+-------------+------+-----+---------+-------+

desc 只回答"表里有哪些列、各是什么类型",六列含义:Field 列名、Type 列类型、Null 是否允许为空、Key 索引情况(主键、外键等约束后续课程展开)、Default 默认值、Extra 附加信息。comment 等更完整的信息 desc 不显示,要看 show create table:返回的正是当初建表的完整语句,包含字符集、校验规则、引擎与每列 comment。它和你敲的原始语句可能不完全一样:SQL 进入服务端后经过词法、语法分析,被规范化为标准写法记录(补齐默认值、统一格式)。MySQL 忠实记录每次结构操作的最终形态,这既是审计痕迹,也是 show create table 能精确回放的依据。

十二、修改表(一):加列与改列属性

表结构修改与改数据是两回事:改结构属 DDL,操作的是表本身。所有结构修改从 alter table 开始,配套 add、modify、drop、change 与 rename 五个动词。以 users 表为例。先插入两行数据作底子(按建表列序给值):

sql 复制代码
insert into users values (1, 'a', 'b', '1982-01-04'), (2, 'b', 'c', '1984-01-04');

1. 加列用 add。 业务场景:用户头像图片不直接入库,图片放 Linux 目录、库里只存路径:

sql 复制代码
alter table users add assets varchar(100) comment '图片路径' after birthday;

after birthday 指定新列插在 birthday 之后(不写则追加到末尾)。desc users 可见五列;select * from users 会发现历史两行的 assets 全是 NULL:新列对老数据零影响,缺的字段自动补空值,这是加列的标准行为。

2. 改列属性用 modify。 把 name 的长度从 20 放宽到 60:

sql 复制代码
alter table users modify name varchar(60);

desc 中 name 已变为 varchar(60),放宽长度不会动已有数据。但此时执行 show create table users\G 会发现 name 列原来的 comment '用户名' 丢了 。原因:modify 是整列覆盖式修改 ,新定义整体替换旧定义,新写法里没带上的属性全部丢失。因此,修改列的某个属性,必须先把该列全部属性原样抄全(用 show create table 取整列定义),只改目标项再提交

sql 复制代码
alter table users modify name varchar(60) comment '用户名';

十三、修改表(二):删列、改表名与改列名

3. 删列用 drop。 password 列不想要了:

sql 复制代码
alter table users drop password;

desc users 只剩四列。drop 列连同该列全部数据永久删除、不可恢复,动手前确认列数据已无用或已备份。

4. 改表名用 rename:

sql 复制代码
alter table users rename to employee;   -- to 可以省略

show tables 中 users 消失、employee 出现。改表名在 Linux 上就是给表文件改名,底层走 mv(移动/重命名)系统调用,与普通文件改名无异;表名随时可改,但上层代码中的表名引用要同步修改。

5. 改列名用 change。 把 name 改成 xingming:

sql 复制代码
alter table employee change name xingming varchar(60);

change 与 modify 的差别在列名:change 把列名连同新定义一起换。与 modify 相同,change 必须给出新列的完整定义(类型、comment 等),不能只写新名字,否则同样丢属性。

五类结构修改收拢如下(modify 与 change 都要带全列定义):

操作 命令骨架 要点
加列 alter table 表名 add 新列完整定义 after 某列 历史行该列自动为 NULL
改列属性 alter table 表名 modify 列名 完整新定义 覆盖式,必须带全原属性
改列名 alter table 表名 change 旧列名 新列名 完整定义 必须带全原属性
删列 alter table 表名 drop 列名 列数据永久删除
改表名 alter table 表名 rename to 新表名 底层 mv,即表文件改名

十四、删除表与结构改动纪律

最后一种结构操作是删表,语法与删库一致:

sql 复制代码
drop table [if exists] t1 [, t2 ...];   -- 一次可删多张

示例:把 users2 删掉:

sql 复制代码
drop table users2;
show tables;    -- 只剩 employee

表一旦 drop,表结构与全部数据从磁盘消失,同样不可恢复。

总结

本篇用一大节完成了库、表两层结构操作的上手,核心是让每条 SQL 都能对应到 Linux 上的动作。

库层面:建库即建目录、删库即删目录 ,防重用 if not exists,可选项集中在字符集与校验规则;字符集决定存储编码,校验规则决定比较与排序语义 ,SQL 显式指定时遵循就近原则。库的查看用 show databases、show create database,进入用 use,确认位置用 select database();修改只涉及编码,MySQL 不支持改库名,库也轻易不删。备份恢复用 mysqldump 配 source:-B 决定备份文件是否含建库语句,备份内容实质是库的完整 SQL 历史,把文件传到另一台机器 source 即可原样重建;show processlist 负责查看连接、排查入侵与慢查询。

表层面:create table 除列定义外可指定字符集、校验规则与引擎,缺省时逐级继承;存储引擎决定磁盘文件形态,MyISAM 三文件(.frm 结构、.MYD 数据、.MYI 索引),InnoDB 两文件(.frm 与数据索引合并的 .ibd)。查看用 show tables、desc、show create table,服务端会把每次结构操作规范化为标准语句记录。结构修改统一走 alter table:add 加列对历史行补 NULL,modify 与 change 是覆盖式操作、必须带全列定义,drop 删列与 drop table 删表均永久不可恢复,rename 改表名对应文件系统的 mv。这些结构操作全部属于 DDL,与操作数据的 DML 相区分。

相关推荐
大虾别跑1 小时前
mysql5.7升级
mysql
geovindu2 小时前
sql: Transaction & Concurrency Patterns using mysql 9.0
mysql·数据库开发·数据库架构
敲代码的瓦龙2 小时前
Jetpack?DataBinding!!!
android·java·开发语言·mysql·android-studio
想念是会呼吸的鱼2 小时前
MySQL 常用语法整理
sql·mysql
不正经的码狗2 小时前
MySQL 免安装教程|安装不报错
mysql
旋生万物2 小时前
MySQL 死锁总复发?用螺旋事务相位互逆法定位加锁顺序(附 Python 诊断脚本)
mysql·大模型·innodb·螺旋生成论·螺旋相位
星光开发者4 小时前
基于Spring Boot的充电桩管理系统的设计与实现-计算机毕设【课程设计】57105
vue.js·spring boot·vscode·mysql·django·php·express
imDwAaY4 小时前
MySQL MVCC 详解:原理、版本链、Read View 与可见性判断
数据库·sql·mysql
Java成神之路-4 小时前
MySQL 约束与索引完全指南
mysql