MySQL零基础保姆级教程:从建库建表到索引优化一次搞懂

MySQL数据库关系型数据库 本内容遵循CC 4.0 BY-SA版权协议
不靠谱的糖饼 不靠谱的糖饼 墨衍会员 · AI 创作全网分发 墨衍智能分发 通过墨衍一键同步至各平台 可同步平台 CSDN微信公众号微博知乎掘金百家号博客园抖音小红书 你的文章也可以这样分发 墨衍会员 ¥399起/年,写一次发全网 我也要

1. 先把"数据库到底在干嘛"这件事说透

零基础学 MySQL,最忌讳的事情就是一上来就背命令。很多教程第一页就甩出 CREATE TABLE,读者连"表"为什么要存在都没搞明白,自然学一个忘一个。所以这篇保姆级教程我特意把"为什么"放在前面,你先想通数据库存在的意义,后面所有语法都会变得顺理成章。

1.1 没有数据库的世界,到底乱成什么样

想象你开了一家小卖部。刚开始用 Excel 记录每天的进货和销售,挺顺手。可一旦顾客多起来、商品类别复杂起来,"多人同时改同一个表怎么办""数据到了几十万行查询变得特别慢怎么办""电脑死机数据没保存怎么办""A同事改的数据把B同事的覆盖了怎么办"——这些问题一个接一个冒出来。

数据库管理系统(DBMS)就是专门解决这些问题的软件。它把数据以结构化方式存储在磁盘上,提供高效查询、并发控制、故障恢复、权限管理等一整套能力。MySQL 就是其中应用最广的开源关系型数据库之一,从个人博客到大型电商平台,到处都有它的身影。

很多初学者容易把"数据库"和"MySQL"这两个概念混在一起,其实 MySQL 只是数据库的一种实现。你可以把"数据库"理解成"汽车"这个大类,MySQL、PostgreSQL、Oracle、SQL Server 都是具体的品牌和车型。

1.2 "关系型"的"关系"两个字,到底指什么

MySQL 属于关系型数据库管理系统(RDBMS)。"关系型"这个词听起来特别学术,拆开理解就一句话:数据以二维表格的形式存放,表与表之间通过相同的字段建立联系。

比如你有两张表:

  • 学生表:学号、姓名、班级
  • 成绩表:学号、科目、分数

成绩表里不需要存学生的姓名,只需要存学号,就能通过"学号"这个共同字段找到学生信息。正因为这种"关系",我们可以用一条 SQL 把两张表的数据连起来查,不需要在每一处都重复存姓名。这就是关系型数据库设计里"减少冗余"的核心思想。

1.3 MySQL 的整体架构:面试会问,理解也不难

不少人搜"mysql架构",其实是想搞明白 MySQL 里面到底是怎么协作的。我建议零基础阶段不需要深究源码,但要把下面这个分层模型记牢,因为它是后续学习优化和排错的基础:

  • 连接层:负责接收客户端的连接请求,做身份验证、权限校验。每次你用 mysql -uroot -p 登录,第一步走的就是这一层。
  • 服务层:SQL 解析、查询优化、内置函数、存储过程、触发器都在这层。你说一句 SELECT * FROM user WHERE id=1,MySQL 先在这里解析成执行计划。
  • 存储引擎层:真正负责数据的读写。MySQL 默认且最常用的是 InnoDB 引擎,支持事务、行级锁、崩溃恢复。不同引擎的存储方式、锁粒度都不同,这是后续性能调优的关键战场。
  • 文件系统层:数据最终以文件形式落到磁盘。datadir 目录下的 .ibd 文件就是 InnoDB 存储真实数据的地方。

打个比方:连接层像公司前台,验证你身份;服务层像项目经理,拆解需求、制定执行方案;存储引擎层像干活的员工,真正执行任务;文件系统层像档案室,所有成果都存在这里。

2. 从零装好 MySQL 环境,每一步都讲清楚

环境搭不起来,后面全是纸上谈兵。我在这些年见过太多人卡在安装这一步,其实大多数坑是有规律可循的。下面把几种常见安装方式都过一遍,你按自己的系统选一种就行。

2.1 版本和下载地址怎么选

初学者经常会搜"mysql下载地址""mysql官网",但到了官网又不知道点哪。我直接说结论:**选 MySQL Community Server 版本即可,这是官方免费社区版,功能和商业版在核心使用上没有任何区别。**下载地址就是 dev.mysql.com/downloads/mysql/。

版本方面,现在主推 8.0 系列(比如 8.0.46)。相比老版本 5.7,8.0 的默认字符集是 utf8mb4、支持窗口函数、支持公用表表达式(CTE),性能也有不少提升。零基础直接学新版本,别在 5.7 上花时间了。

2.2 Windows 安装:MSI 向导和 ZIP 压缩包两种办法

方式一:MSI 安装包,适合不想折腾的人

下载 mysql-installer-community-8.0.xx.msi,双击开始安装。需要注意几步:

  • 选择 Setup Type 时,选 Server only 就够了,其他组件以后需要再装。
  • 到 "Type and Networking" 这一步,端口保持默认的 3306。如果本机 3306 被占用(常见于之前装过其他数据库),可以改成 3307。
  • 认证方式建议选 "Use Strong Password Encryption"。
  • 设置 root 密码时,一定要记牢,或者直接存到密码管理工具里。
  • 最后一步配置 Windows Service,勾选开机自启动,方便省事。

方式二:ZIP 压缩包,自己掌控一切

很多人在搜"mysql 8.0.46 压缩版安装",这种方式的本质就是手动初始化并注册服务。步骤如下:

  1. 把压缩包解压到 D:\mysql-8.0.46-winx64。
  2. 在根目录新建 my.ini 配置文件:
INI
[mysqld]
basedir=D:/mysql-8.0.46-winx64
datadir=D:/mysql-8.0.46-winx64/data
port=3306
character-set-server=utf8mb4
default-storage-engine=InnoDB
 
[client]
default-character-set=utf8mb4
  1. 以管理员身份打开 CMD,进入 bin 目录,执行初始化命令:
BASH
mysqld --initialize-insecure

注意:这里用 --initialize-insecure 会生成一个空密码的 root 用户,适合新手首次登录。如果用了 --initialize,系统会生成随机密码并把密码写在 data 目录下的 .err 日志文件里,很多新手找不到这个文件,白白卡住。

  1. 注册成 Windows 服务并启动:
BASH
mysqld --install mysql8
net start mysql8

以后你可以直接在 Windows 服务管理面板里启停 MySQL,也可以用 net stop mysql8 停止。

2.3 Docker 安装:一条命令搞定

如果你用 Docker,安装 MySQL 可能是所有方式里最省心的。很多人搜"docker安装mysql",核心命令就这几行:

BASH
docker pull mysql:8.0
docker run -d \
--name mysql8 \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=123456 \
mysql:8.0

注意几个参数的含义:

  • -d 表示后台运行。
  • --name mysql8 给容器起个名。
  • -p 3306:3306 把容器内的 3306 端口映射到宿主机,这样外部程序才能通过宿主机 IP 访问数据库。
  • -e MYSQL_ROOT_PASSWORD=123456 设置 root 密码。

如果要指定字符集,可以在命令后面加:

BASH
docker run -d --name mysql8 -p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=123456 \
mysql:8.0 \
--character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci

我第一次用 Docker 装 MySQL 时,忘了设置字符集,建表时插入中文全是问号。后来排查发现容器默认的 character_set_server 不是 utf8mb4,教训深刻。

2.4 客户端工具:命令行、Workbench、Navicat 怎么选

装好服务端之后,你需要一个"入口"去操作它。

  • 命令行 mysql:装 MySQL 自带的客户端,敲 mysql -uroot -p 进入。虽然界面简陋,但它是排查问题最直接的工具,零基础阶段建议先用它,能让你理解每条命令的执行流程。
  • MySQL Workbench:官方免费图形化工具,支持建表可视化、ER 图、查询执行计划查看。适合不想记语法的人,也适合做数据建模。
  • Navicat for MySQL:第三方商业工具,界面真的很顺手,导入导出也方便。很多人在搜"navicat for mysql 免费版",它确实有试用期,正版需要付费购买。预算有限的用户可以用 Workbench 平替,功能上完全够用。

我的建议是:前期命令行为主,图形工具为辅。 遇到报错时,命令行能告诉你最原始的错误信息,这对学习排错至关重要。

3. 建库建表:数据模型是地基,先学会画这张表

环境跑通之后,就进入正式实操了。先记住 SQL 的两个基本规矩:语句以分号结尾,关键字不区分大小写但习惯上大写(我下面的示例用小写更贴近实战习惯,你也可以全大写,效果一样)。

3.1 创建和删除数据库

SQL
SHOW DATABASES;
CREATE DATABASE shop DEFAULT CHARACTER SET utf8mb4;
USE shop;

创建数据库时显式指定 utf8mb4 字符集非常重要。MySQL 8.0 虽然默认就是 utf8mb4,但老版本默认是 latin1,存中文会变成乱码。utf8mb4 是完整的 UTF-8 实现,不仅支持中文,还支持 emoji 表情,现在做新项目基本都选它。

删除数据库用 DROP DATABASE shop;,这句命令会把整个库连同数据全部删掉,执行前一定要三思。生产环境我几乎不用 DROP,更常用的是先备份再改名。

3.2 数据类型别乱选,先记这几种就够了

建表时最纠结的往往是"这个字段该用什么类型"。我把日常开发出现频率最高的类型整理成一张表:

类别 数据类型 使用场景
整数 INT, BIGINT 数量、ID、订单号等
小数 DECIMAL(10,2) 金额、价格
字符串 VARCHAR(255) 用户名、手机号、邮箱
长文本 TEXT, LONGTEXT 文章正文、备注
日期时间 DATETIME, TIMESTAMP 创建时间、更新时间
布尔 TINYINT(1) 状态标志,0 和 1

一个经典教训:金额绝对不能用 FLOAT 或 DOUBLE 存。浮点数是近似值,0.1 + 0.2 在计算机里可能算出 0.30000000000000004,线上账目一旦用浮点算金额,对不上账就是分分钟的事。金额正确姿势是 DECIMAL(10,2),它是定点数,按整数方式存储,精确可靠。

3.3 主键、唯一键、外键:这些约束到底在约束什么

主键(PRIMARY KEY) 是每行记录的唯一标识。一个表只能有一个主键,主键值不能为空,通常用自增整数或 UUID。自增主键简单高效,是新手最稳妥的选择。

唯一键(UNIQUE KEY) 保证一列或多个列的组合值不重复。比如用户表里的 username 通常要加唯一约束,防止注册重名。一个表可以有多个唯一键。注意主键本身也包含唯一性约束。

外键(FOREIGN KEY) 用来维护表间数据的一致性。比如订单表的 user_id 引用用户表 id,如果用户被删除,订单里的关联数据怎么处理?外键的 ON DELETE CASCADE 或 ON DELETE SET NULL 可以控制这种行为。

不过实际开发中,很多团队出于性能考虑,选择不建物理外键,而是在应用层维护数据关系。这样做的好处是插入、更新更快,坏处是数据一致性靠代码保证,容易出 bug。面试时能讲出这个取舍,会显得你理解了本质。

3.4 建表语句实战

下面创建一个用户表,几乎涵盖日常建表 90% 的场景:

SQL
CREATE TABLE user (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
nickname VARCHAR(50) DEFAULT '',
age TINYINT UNSIGNED DEFAULT 0,
balance DECIMAL(12,2) DEFAULT 0.00,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

几个细节逐一说一下:

  • BIGINT UNSIGNED:无符号大整数,取值范围比普通 BIGINT 大,用作主键基本不会爆。
  • AUTO_INCREMENT:自增列,每次插入自动加 1,不用手动赋值。
  • NOT NULL UNIQUE:既约束非空,又要求唯一,防止重复用户名。
  • DEFAULT CURRENT_TIMESTAMP:插入时自动生成当前时间,省去应用层传参。
  • ON UPDATE CURRENT_TIMESTAMP:更新记录时自动修改 updated_at,做数据审计非常好用。
  • ENGINE=InnoDB:8.0 默认就是 InnoDB,写不写都行,但写上能提醒你关注引擎差异。

3.5 修改表结构是家常便饭

项目需求一变,加字段、删字段、改类型是常有的事。

SQL
-- 新增一列,放在 nickname 后面
ALTER TABLE user ADD COLUMN phone VARCHAR(20) AFTER nickname;
 
-- 修改列的数据类型
ALTER TABLE user MODIFY COLUMN phone VARCHAR(30);
 
-- 修改列名
ALTER TABLE user CHANGE COLUMN phone mobile VARCHAR(30);
 
-- 删除列
ALTER TABLE user DROP COLUMN mobile;
 
-- 查看当前表结构
DESC user;

ALTER TABLE 在大表上执行时可能锁表,生产环境要选择合适的时机或者用在线 DDL 工具。零基础阶段先掌握命令本身,优化意识等有项目经验了再培养。

4. 增删改查:MySQL 最核心的四个动作

CRUD 是日常开发里执行频率最高的操作,也是面试题的高发区。下面我从实际场景出发,把四种操作一次讲透。

4.1 INSERT:插入数据的正确姿势

SQL
INSERT INTO user (username, nickname, age)
VALUES ('zhangsan', '张三', 20);

注意到我没有插入 id、created_at 等字段,因为它们有默认值或自增。一次插入多条数据时,一条 INSERT 的多 VALUES 写法比循环逐条插入效率高得多:

SQL
INSERT INTO user (username, nickname, age) VALUES
('lisi', '李四', 21),
('wangwu', '王五', 25);

实际项目中,如果要从另一张表批量导入数据,常用 INSERT INTO ... SELECT:

SQL
INSERT INTO user_backup (username, nickname, age)
SELECT username, nickname, age FROM user WHERE age > 18;

4.2 SELECT:筛选、分组、排序一次讲明白

查询是重中之重。基础查询:

SQL
SELECT id, username, nickname FROM user WHERE age >= 18;

按年龄分组,统计每个年龄段有多少人:

SQL
SELECT
CASE
WHEN age < 18 THEN '未成年'
WHEN age < 30 THEN '青年'
ELSE '中年及以上'
END AS age_group,
COUNT(*) AS cnt
FROM user
GROUP BY age_group
ORDER BY cnt DESC;

这里用了 CASE WHEN 做条件分组、COUNT(*) 聚合统计、GROUP BY 分组、ORDER BY 排序,一条语句串起了查询的核心能力。注意执行顺序:先 WHERE 过滤,再 GROUP BY 分组,再聚合函数计算,最后 ORDER BY 排序。

4.3 排序和分页:数据库命令大全里最常用的组合

SQL
-- 按余额从高到低
SELECT * FROM user ORDER BY balance DESC;
 
-- 按创建时间倒序,时间相同时按 id 正向
SELECT * FROM user ORDER BY created_at DESC, id ASC;
 
-- 分页:每页 20 条,第 3 页
SELECT * FROM user ORDER BY id LIMIT 20 OFFSET 40;

LIMIT 20 OFFSET 40 等价于 LIMIT 40, 20,表示跳过 40 条再取 20 条。页码和偏移的关系是 offset = (page - 1) * pageSize。

新手常犯的错误是 LIMIT 后面两个数字顺序搞反。LIMIT 20, 40 和 LIMIT 40, 20 返回的结果完全不一样,排查时先确认书写顺序。

4.4 mysql 8.0 的窗口函数:分组内排序的利器

很多人搜"mysql排序",其实是想做"每个分组内取前几名"这种需求。在 8.0 之前,这类需求要写子查询或者用户变量,非常绕。8.0 引入窗口函数后,一条 SQL 搞定:

SQL
-- 按年龄分组,组内按余额从高到低排序编号
SELECT
username, age, balance,
ROW_NUMBER() OVER (PARTITION BY age ORDER BY balance DESC) AS rn
FROM user;

PARTITION BY age 就是"按年龄分桶",ORDER BY balance DESC 是桶内排序,ROW_NUMBER() 给每行一个序号。想取每组前三名,外面再包一层:

SQL
SELECT * FROM (
SELECT
username, age, balance,
ROW_NUMBER() OVER (PARTITION BY age ORDER BY balance DESC) AS rn
FROM user
) t
WHERE rn <= 3;

零基础阶段先把普通 GROUP BY 练熟,窗口函数作为进阶加分项,能写出这条,面试官对你的好感会明显上升。

4.5 UPDATE:更新子查询要注意自引用陷阱

简单更新:

SQL
UPDATE user SET balance = balance + 50 WHERE id = 1;

很多人搜"mysql中更新子查询",核心痛点在于 MySQL 不允许在 UPDATE 里直接查询并更新同一张表。报错信息通常是 You can't specify target table for update in FROM clause。

比如你想给余额最高的人名字加上 "VIP":

SQL
UPDATE user
SET nickname = CONCAT(nickname, 'VIP')
WHERE id = (SELECT MAX(id) FROM user);

上面这句就会报错,因为子查询和目标表是同一张表。解决办法是包一层派生表,让 MySQL 认为外层已经换了一张虚拟表:

SQL
UPDATE user
SET nickname = CONCAT(nickname, 'VIP')
WHERE id = (
SELECT id FROM (
SELECT MAX(id) AS id FROM user
) t
);

核心思路一句话:update 子查询要绕一层,不要让 MySQL 发现在边查边改同一张表。

4.6 DELETE:删除操作的保命原则

简单删除:

SQL
DELETE FROM user WHERE id = 100;

删全表:

SQL
TRUNCATE TABLE user;

TRUNCATE 和 DELETE 不一样:TRUNCATE 直接清空整个表并重置自增 ID,速度快但不能带条件、不能回滚;DELETE 可以带条件,逐行删,配合事务可以回滚。

我给新手的保命建议是:任何 DELETE 执行前,先把 WHERE 条件改成 SELECT 跑一遍,确认影响行数是你预期中的数量,再执行删除。

SQL
SELECT * FROM user WHERE age > 60; -- 先数一下
DELETE FROM user WHERE age > 60; -- 再删

这个习惯养成之后,能帮你躲过绝大多数线上事故。

5. 索引与性能:让查询从"龟速"变"秒回"的关键

数据库性能优化是个大话题,但零基础阶段只需要抓住一个核心——索引。面试中考索引的频率极高,实战中排查慢查询也绕不开它。

5.1 索引的本质:用空间换时间

索引的原理可以理解成一本书的目录。没有目录时,要在 500 万行数据里找一条记录,只能一行行扫描,这叫做全表扫描,慢到没朋友。有了索引之后,MySQL 通过 B+ Tree 树形结构,能在几十毫秒内定位到目标行,效率是数量级的提升。

代价是索引需要额外占用磁盘空间,每次 INSERT、UPDATE、DELETE 时还要同步维护索引树,所以写操作会变慢。这就是"空间换时间、读快写慢"的权衡。

常见索引类型:

  • 普通索引(INDEX):加速查询,不要求唯一。
  • 唯一索引(UNIQUE KEY):加速查询,同时保证值唯一。
  • 联合索引(复合索引):多个列组合成一个索引,遵循最左前缀原则。
  • 全文索引(FULLTEXT):用于全文检索,实际项目里中文全文检索往往交给 Elasticsearch 这类专用系统。

5.2 创建索引的正确姿势和最左前缀原则

SQL
-- 普通索引
CREATE INDEX idx_username ON user(username);
 
-- 唯一索引
CREATE UNIQUE INDEX idx_username_unique ON user(username);
 
-- 联合索引,字段顺序有讲究
CREATE INDEX idx_age_balance ON user(age, balance);
 
-- 查看表上所有索引
SHOW INDEX FROM user;
 
-- 删除索引
DROP INDEX idx_username ON user;

联合索引的列顺序很关键。idx_age_balance 建立在 (age, balance) 两个字段上,它能高效命中以下查询:

SQL
WHERE age = 20
WHERE age = 20 AND balance > 100

但对单独用 balance 过滤的查询,这个索引是无效的,因为 B+ Tree 结构先按 age 排序,再按 balance 排序。这就是最左前缀原则:必须从索引最左边的列开始匹配,中间不能跳过。

所以联合索引字段顺序一般遵循两个原则:一是区分度高的列放前面,二是经常等值查询的字段放前面。

5.3 用 EXPLAIN 看一条 SQL 走没走索引

EXPLAIN 是 MySQL 提供的执行计划分析工具,在 SELECT 前面加一个 EXPLAIN 关键字即可:

SQL
EXPLAIN SELECT * FROM user WHERE username = 'zhangsan';

返回结果里重点看这几个字段:

  • type:连接类型。从好到差大致是 const > eq_ref > ref > range > index > ALL。看到 ALL 就要警惕,说明是全表扫描。
  • key:实际使用的索引名。如果是 NULL,可能没走索引。
  • rows:预估扫描行数,越小越好。

比如你建了索引但 type 还是 ALL,常见原因包括:

SQL
-- 在索引列上使用函数,导致索引失效
EXPLAIN SELECT * FROM user WHERE YEAR(created_at) = 2024;
 
-- 改成范围比较,索引就能生效
EXPLAIN SELECT * FROM user WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01';

SQL 写法对索引的影响非常大,这个知识点面试和实际排查中都极其高频。

6. 事务、存储过程、视图:入坑进阶前要知道的三大件

掌握前面的内容,日常增删改查基本没问题了。但想应对真实项目和面试,下面这几个特性必须理解。

6.1 事务的 ACID,不只是四个字母

事务是"一组要么全部成功、要么全部失败"的操作。最经典的例子是转账:A 转给 B 100 元,包含 A 扣 100、B 加 100 两步操作,任何一步失败,整个操作都应该回滚,否则账就对不上了。

事务的四个特性,缩写 ACID:

  • 原子性(Atomicity):事务内操作不可分割,要么全做,要么全不做。
  • 一致性(Consistency):事务执行前后,数据总量和业务规则保持一致。
  • 隔离性(Isolation):多个事务并发执行时互不干扰。MySQL 通过锁和 MVCC 实现不同的隔离级别。
  • 持久性(Durability):事务提交后,即使系统崩溃,修改也必须永久保存。

MySQL 中使用事务很简单:

SQL
START TRANSACTION;
 
UPDATE account SET balance = balance - 100 WHERE id = 1;
UPDATE account SET balance = balance + 100 WHERE id = 2;
 
COMMIT;
-- 如果中途发现异常,执行 ROLLBACK 回滚

我看过不少线上事故就是"存储过程里多步 UPDATE 没包事务",第一步成功、第二步失败,数据就错乱了。养成"涉及多表写操作就开事务"的习惯很重要。

6.2 存储过程:封装一段复杂 SQL 逻辑

存储过程就是把一段复杂的 SQL 逻辑保存在数据库端,应用调用时传参数即可。它可以减少网络往返,也能统一管理业务 SQL。很多人搜"mysql存储过程""mysql储存过程+错误信息",核心需求其实是如何处理存储过程中的报错。

下面是一个带错误处理的转账存储过程:

SQL
DELIMITER //
 
CREATE PROCEDURE sp_transfer(IN from_id INT, IN to_id INT, IN amount DECIMAL(12,2))
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
SELECT '转账失败,已回滚' AS msg;
END;
 
START TRANSACTION;
UPDATE account SET balance = balance - amount WHERE id = from_id;
UPDATE account SET balance = balance + amount WHERE id = to_id;
COMMIT;
SELECT '转账成功' AS msg;
END//
 
DELIMITER ;

调用:

SQL
CALL sp_transfer(1, 2, 100.00);

DECLARE EXIT HANDLER FOR SQLEXCEPTION 是这里最关键的语句。它声明了一个"如果在执行过程中遇到任何 SQL 异常,就回滚事务并退出"的处理器。没有它,存储过程里的错误不会自动处理,事务可能悬在半空中。

注意 DELIMITER // 的作用:默认 MySQL 用分号作为语句分隔符,但存储过程内部本身就有分号,所以要临时把分隔符改成一个不常用的符号,等存储过程建完再改回来。

6.3 视图和触发器:封装与自动化的两个武器

视图(VIEW) 本质是一条保存起来的 SELECT 查询,可以当成虚拟表使用。

SQL
CREATE VIEW v_user_overview AS
SELECT id, username, balance
FROM user
WHERE balance > 0;
 
-- 之后可以直接查询
SELECT * FROM v_user_overview;

视图的好处是隐藏复杂逻辑、简化重复查询。视图不存数据,每次查询都是动态执行底层 SQL。注意不要在大表上创建太多嵌套视图,性能容易出问题。

触发器(TRIGGER) 是当表发生 INSERT、UPDATE、DELETE 时自动执行的一段 SQL。比如每次更新订单表时,自动记录一条日志:

SQL
CREATE TRIGGER trg_user_update
AFTER UPDATE ON user
FOR EACH ROW
INSERT INTO user_log(user_id, old_balance, new_balance, updated_at)
VALUES (OLD.id, OLD.balance, NEW.balance, NOW());

OLD 表示更新前的行,NEW 表示更新后的行。触发器好用,但别放太重逻辑,否则会拖慢每次写入速度。零基础阶段了解概念、知道场景即可。

7. 日常运维:备份、连接和常见故障排查

很多新手以为把 SQL 写好就完事了。实际上,数据库的稳定运行依赖日常运维习惯。这几项技能不学,等出问题时往往已经来不及。

7.1 定时备份,保命的第一道防线

数据是无价的。硬盘会坏、误删会犯、上线脚本可能写错条件。我的经验是:不管项目多小,一定要有自动备份。

最常用的逻辑备份工具是 mysqldump:

BASH
# 备份整个数据库
mysqldump -u root -p shop > shop_backup.sql
 
# 备份单张表
mysqldump -u root -p shop user > user_backup.sql
 
# 恢复
mysql -u root -p shop < shop_backup.sql

备份出来的 SQL 文件是纯文本,里面一条条 CREATE TABLE 和 INSERT 语句,可以跨版本迁移,也算一种可读文档。

7.2 自动备份 bat 脚本,Windows 用户照着抄

很多人搜"mysql自动备份bat",我直接把一套能用的脚本放上来。在 Windows 上配合"任务计划程序"就能实现每日自动备份。

BAT
@echo off
set BACKUP_DIR=D:\mysql_backup
set DB_NAME=shop
set MYSQL_HOME=C:\Program Files\MySQL\MySQL Server 8.0\bin
set DATE_TAG=%date:~0,4%%date:~5,2%%date:~8,2%
 
if not exist "%BACKUP_DIR%" mkdir "%BACKUP_DIR%"
 
"%MYSQL_HOME%\mysqldump" -u root -p123456 %DB_NAME% > "%BACKUP_DIR%\%DB_NAME%_%DATE_TAG%.sql"
echo backup success: %DB_NAME%_%DATE_TAG%.sql

实际使用中有几个要点:

  • bat 脚本里的密码是明文,安全敏感场景建议用 mysqldump --defaults-extra-file=/path/to/backup.cnf 指向一个权限受限的配置文件,密码写在 cnf 里而不是命令行上。
  • %date% 的格式依赖系统区域设置,最好先 echo %date% 确认格式,再决定截取哪些位。
  • 备份文件会越积越多,建议在脚本末尾加清理命令,只保留最近 30 天:
BAT
forfiles /p "%BACKUP_DIR%" /s /m *.sql /d -30 /c "cmd /c del @path"
  • 定时任务的触发器设置建议选"每天"运行一次,尽量选凌晨业务低峰期,比如凌晨 2 点。

7.3 连不上 MySQL?按这个顺序排查

我在社区看到最多的求助帖就是"mysql 连接不上"。这类问题大多是下面几个原因之一,按顺序查基本都能解决:

  1. 服务没启动:Windows 下看服务管理器里 mysql 状态,Linux 下执行 systemctl status mysqld。
  2. 端口不对或被占用:默认是 3306,先试 mysql -uroot -p -P 3306 能不能连。用 netstat -ano | findstr 3306 看端口监听情况。
  3. 账号权限不够:root 默认一般只允许本机登录。要从远程连接,需要单独建账号并授权。
  4. 防火墙或安全组:云服务器上连接超时,多数原因是安全组没开放 3306 端口。本机测试先关掉防火墙试试。

7.4 连接池是什么,为什么程序要管连接

很多人搜"mysql的数据库连接池",这里简单讲一下。每次新建一个数据库连接,需要经过 TCP 握手、认证、权限校验等流程,耗时可达毫秒甚至几十毫秒。如果高并发下每个请求都新建连接,数据库很快就会被连接请求打垮。

连接池就是预先创建一批连接,程序用的时候从池里取,用完放回池里,重复利用。Java 里的 HikariCP、Druid,Go 里的 database/sql 连接池,都在干这件事。零基础阶段理解到这个层面就够,等你写项目时自然会接触到具体配置。

8. 高频面试点与新手必踩的坑,一次整理给你

有些知识点在热搜词和面试题里反复出现,说明它们确实是区分"会点"和"懂行"的分水岭。下面把几个最重要的集中讲透。

8.1 面试三问:引擎、字符、优化

MyISAM 和 InnoDB 有什么区别?

  • InnoDB 支持事务、外键、行级锁,支持崩溃恢复;MyISAM 不支持事务和外键,使用表级锁,查询速度在某些场景下稍快,但并发写性能差。
  • 8.0 之后 MyISAM 虽然还存在,但已经不是主流。记住一句话:默认选 InnoDB,没有特殊理由不要换。

char 和 varchar 怎么选?

  • char(n) 是定长,varchar(n) 是变长。char 在值不足 n 时右补空格,取出来再去掉,浪费空间但存取简单,适合固定长度的值,如手机号、身份证号。
  • varchar 只存实际字符长度加 1-2 字节的长度信息,省空间,是绝大多数场景的首选。

深分页怎么优化?

LIMIT 100000, 10 这种深分页之所以慢,是因为 MySQL 要先扫 10 万行再扔到 10 万行,前面的 10 万行全是无用功。优化思路是"延迟关联"或"基于游标":

SQL
-- 延迟关联:先在索引上找到起点主键,再回表取详情
SELECT * FROM user
WHERE id > (
SELECT id FROM user ORDER BY id LIMIT 100000, 1
)
ORDER BY id
LIMIT 10;

只查主键列的扫描开销远小于全行扫描,特别适合大表分页。

8.2 整数类型怎么选,mysql 可以存哪些整数

有人搜"mysql可以存储整数数值的是"这种问题,说明大家对类型范围没概念。MySQL 整数类型及范围如下:

类型 取值范围(有符号) 常见用途
TINYINT -128 ~ 127 状态码、0/1标记
SMALLINT -32768 ~ 32767 较小数值
MEDIUMINT -8388608 ~ 8388607 中规中矩
INT -2147483648 ~ 2147483647 业务编号、数量
BIGINT 更大范围 自增主键、订单号

日常建议:主键用 BIGINT UNSIGNED,状态用 TINYINT,一般计数用 INT。

8.3 字符串大小写和字符集相关的问题

有热搜词提到"kingbase mysql模式字符串不区分大小写咋回事",这其实涉及 MySQL 的排序规则。MySQL 的字符串比较是否区分大小写,取决于列的 collation。

  • utf8mb4_general_ci 里的 _ci 表示 case-insensitive,即不区分大小写,默认常用。
  • utf8mb4_bin 表示二进制比较,区分大小写。
SQL
-- 建表时指定区分大小写
CREATE TABLE user (
code VARCHAR(50) COLLATE utf8mb4_bin NOT NULL
) DEFAULT CHARSET=utf8mb4;

如果发现两条字符串 'ABC' 和 'abc' 被当成相同值,去查表的 collation 和列级别的 collation,大概率是 _ci 排序规则导致的。

8.4 端口问题和多个 MySQL 共存

默认端口是 3306。一台机器上同时装 MySQL 5.7 和 8.0 时,可以让两个实例分别监听不同端口,比如 3306 和 3307。连接时用 -P 3307 指定端口,注意是大写 P,小写 -p 是密码参数。这个大小写问题坑过很多新手:

BASH
mysql -uroot -p123456 -P3307

8.5 mysqldump 导入导出大文件时要注意什么

用 mysqldump 导出的 SQL 文件如果特别大,直接用 GUI 工具导入容易卡死或超时。更稳的方式是进入命令行客户端后使用 source:

SQL
source D:/shop_backup.sql;

如果导入时遇到 max_allowed_packet 超限报错,可以临时调大这个参数:

SQL
SET GLOBAL max_allowed_packet = 64 * 1024 * 1024;

导入大批量数据时,还可以临时关闭自动提交和唯一约束检查,等全部导入完再审一遍。不过这个操作要谨慎,非生产环境可以放心用。

写到这里,MySQL 入门所需的主干知识点差不多齐了。我个人的学习心得是:**不要试图一次性背完所有知识点,而是先把环境跑起来,跟着把建库、建表、增删改查完整走一遍,再带着问题去学索引、事务、备份这些进阶内容。**数据库是极度依赖实操的领域,看的再多,不如自己真枪实弹跑几条命令记得牢。

如果中途卡住,优先看报错信息原文,其次拿报错语句去搜索引擎查,而不是笼统地搜"mysql 报错"。很多坑不是你一个人踩过,网上一定有人碰到完全一致的情况。

最后再分享一个学习方法:给自己建一个练习库,模拟一个简单的电商订单系统,每天写几条 SQL 查订单、查用户、统计销售额。这种"以业务带学习"的方式,比零散背 SQL 词条高效得多。等你有一天能随手写出多表 JOIN、子查询、分组统计的时候,MySQL 就算真正入门了。

相关推荐

基于Python+Open CV的手势识别算法设计

伴随着人工智能时代的到来,人机交互的领域也逐渐成为研究的一大方向;其中,手势识别是人机交互领域的一项关键技术,自此手势识别也迎来了一波高潮,近几年无论是在消费领域、电子领域、数码领域、家电领域甚至汽车领域上,都能或多或少的见到手势识别的身影。 手势识别在设计智能高效的人机界面方面具有至关重要的作用, 目前手势识别已应用到手语识别、智能监控、到虚拟现实等各个领域,手势识别的原理都是利用各种传感器(例如红外、摄像头等)对手部的形态进行捕捉并进行建模,形成一个模型信息的序列帧,而后将这些信息序列转换为机器能够识别的相对应指令(例如打开、切换菜单、移动等)来完成控制。 采用Python的集成开发环境Pycharm进行本次课程设计,在Pycharm中进行需要库(模块)的下载,调取电脑摄像头,按帧读取摄像头采集到的头像,形态学处理,图像旋转(由于摄像头采集到的图像是镜像,需要用cv2.flip将摄像头采集到的图像进行处理),选取图片中固定位置作为手势输入,用红线画出手势识别框,基于hsv的肤色检测,进行高斯滤波,找出轮廓,求出图像中手势的凹凸点,手指间角度求取。

努力学习前端的小陈

ROS-CV-ImageConverter:将ROS图像转换为OpenCV(cv :: Mat)类型的图像

ROS-CV图像转换器 依存关系 cv_bridge(ROS软件包)

Willis Wang

计算机视觉图像处理-CV2与图像插值算法

用最近邻插值与双线性插值原理完成图像缩放 最近邻插值,是指将目标图像中的点,对应到源图像中后,找到最相邻的整数点,作为插值后的输。缺点:使用最近邻插值算法处理图像放大时,在图象中可能出现明显的块状效应 双线性插值,在两个方向上做三次线性插值。使用双线性插值算法处理图像放大时,在图象中可能出现马赛克 代码 import cv2 img = cv2.imread(’./xiabang.jpg’, cv2.IMREAD_UNCHANGED) #缩放比例 scale_percent = 0.3 width = int(img.shape[1] * scale_percent) height = int

weixin_38697274

基于水平集CV模型的图像分割(Matlab代码)

基于水平集CV模型的图像分割(Matlab代码),全套代码

小宇QAQ

导向滤波(guide_filter)的python实现

导向滤波(guide_filter)的python实现,可以结合暗通道;理论实现比较好的图像去噪效果。

zachzhan_g
返回顶部
不靠谱的糖饼
博客等级 码龄8年 37粉丝 8,394原创