你是否也有过这样的经历:
想入行后端开发、数据分析、测试运维,却卡在MySQL这道坎,对着满屏的SQL语句无从下手?
背了无数遍CRUD,真到写业务SQL时,要么逻辑混乱写不出来,要么跑起来巨慢被leader吐槽?
面试时被问到MySQL的基础概念就支支吾吾,连char和varchar的核心区别都说不清楚?
别慌,这不是你笨,而是你没有找到一套成体系、从零基础循序渐进的学习路径。
本系列《零基础从入门到精通MySQL》,将分为**上篇(筑基篇)、中篇(进阶篇)、下篇(精通篇)、附加篇(面试八股文全集)**四大模块,从最基础的环境搭建、核心概念,到进阶的索引、事务、锁机制,再到高阶的性能优化、集群架构,最后配套全覆盖的面试八股文,带你一步一个脚印,从SQL小白成长为MySQL实战高手。
本篇作为系列的开篇------筑基篇,我们将彻底抛弃碎片化的知识点,从零开始,帮你打牢MySQL的核心地基。学完本篇,你将能独立完成数据库、表的规范设计与维护,熟练写出90%业务场景下的基础SQL语句,彻底摆脱"只会背命令,不懂为什么"的困境。
系列整体规划(提前锁定学习路径)
- 上篇(筑基篇):MySQL核心认知、环境全场景搭建、核心数据模型、基础SQL语法(DDL/DML/DQL基础/DCL)、单表查询全解
- 中篇(进阶篇):多表关联查询、子查询、视图、存储过程、函数、触发器、事务核心原理与ACID特性
- 下篇(精通篇):索引底层原理与设计规范、锁机制、MVCC多版本并发控制、执行计划解析、SQL性能优化、集群架构、备份与恢复
- 附加篇(八股文全集):从基础到高阶全覆盖的MySQL面试题,附标准答案与答题思路,适配校招、社招全场景
第一章 先搞懂:MySQL到底是什么?为什么非学不可?
1.1 MySQL的核心定位
MySQL是一款开源免费的关系型数据库管理系统(RDBMS),由瑞典MySQL AB公司开发,目前隶属于Oracle。所谓关系型数据库,就是用二维表格的形式来组织和存储数据,通过行和列的结构化方式,实现数据的高效管理和关联查询。
为什么说MySQL是入行IT行业的必修课?
- 市场占有率第一:互联网行业的标配数据库,淘宝、京东、字节、腾讯等大厂的核心业务均基于MySQL构建,校招、社招后端、数分、测试、运维岗位,MySQL是100%的必考内容
- 开源轻量,生态完善:社区活跃,文档丰富,有大量的配套工具和解决方案,学习成本低,部署维护简单
- 跨平台兼容:支持Windows、Linux、MacOS全平台,适配Docker、K8s等容器化部署,无论是本地开发还是线上生产都能无缝适配
- 功能强大,扩展性强:支持千万级数据量的稳定运行,插件式存储引擎架构,支持事务、索引、高可用集群等企业级特性
1.2 MySQL极简核心架构(零基础先建立全局认知)
很多人学MySQL只盯着SQL语句,却不知道自己写的SQL在MySQL里是怎么执行的,导致遇到问题无从排查。这里我们先给MySQL的架构做个极简拆解,先建立整体认知,后续章节会逐步深入:
MySQL的核心架构分为3层,从上到下依次是:
- 连接层:负责客户端连接管理、权限验证、安全校验。比如你用Navicat、DBeaver、代码里的JDBC连接数据库,都是这一层在处理,同时会验证你的用户名、密码、主机访问权限。
- 服务层:MySQL的核心SQL处理层,你写的所有SQL语句,都是在这里完成解析、优化、执行的。包括SQL解析器、查询优化器、执行器、缓存组件等,核心功能都在这一层实现。
- 存储引擎层 :负责数据的实际存储和提取,是MySQL的底层核心。MySQL的特色就是插件式存储引擎,不同的存储引擎有不同的特性,最常用的就是InnoDB(MySQL5.5之后的默认存储引擎,支持事务、行锁、外键)和MyISAM(不支持事务,仅支持表锁,现在基本被淘汰)。
简单来说:你写的SQL语句,先通过连接层验证身份,再到服务层解析优化成执行计划,最后通过存储引擎层去磁盘上读写数据。
第二章 零基础零踩坑:MySQL环境全场景搭建
学MySQL的第一步,就是搭建一套属于自己的学习环境,很多人在这里就因为各种安装报错放弃了。这里我们覆盖Windows、MacOS、Linux、Docker四大场景,一步一步带你完成安装,全程零踩坑。
2.1 版本选择
优先选择MySQL 8.0.x 稳定版,原因如下:
- MySQL 5.7已经停止官方维护,后续不会有安全更新,企业正在逐步迁移至8.0
- 8.0版本在性能、安全性、功能上有巨大提升,优化了查询优化器、支持窗口函数、CTE、原子DDL等高级特性
- 现在企业招聘的核心要求都是熟练使用MySQL8.0,学习8.0可以直接匹配企业需求
2.2 Windows环境安装
- 下载安装包:进入MySQL官网,下载MySQL Installer for Windows(社区版),选择完整安装包。
- 安装步骤 :
- 打开安装包,选择
Developer Default(开发者默认配置,包含服务端、客户端、开发工具等),点击下一步 - 安装依赖:如果提示缺少VC++运行库,点击安装即可,完成后继续下一步
- 配置类型选择
Development Computer(开发机配置,占用资源少,适合学习) - 端口默认3306,不要修改,开启TCP/IP协议,点击下一步
- 身份验证方式,选择
Use Strong Password Encryption(强密码加密,8.0默认) - 设置root用户密码,务必记住这个密码,后续登录需要使用,建议设置大小写+数字+特殊字符的强密码
- 配置Windows服务,服务名默认MySQL80,勾选开机自启(可选),点击下一步
- 后续步骤全部默认,点击执行,等待安装完成即可
- 打开安装包,选择
- 验证安装是否成功 :
- 按下Win+R,输入cmd,打开命令提示符
- 输入命令
mysql -u root -p,回车后输入你设置的root密码 - 如果出现
mysql>提示符,说明安装成功,已经进入MySQL命令行环境
2.3 Linux环境安装(CentOS 8/9为例)
线上生产环境90%都是Linux系统,所以必须掌握Linux下的MySQL安装:
bash
# 1. 配置MySQL官方yum源
sudo rpm -ivh https://dev.mysql.com/get/mysql80-community-release-el8-3.noarch.rpm
# 2. 安装MySQL社区版服务端
sudo yum install -y mysql-community-server
# 3. 启动MySQL服务,并设置开机自启
sudo systemctl start mysqld
sudo systemctl enable mysqld
# 4. 查看服务运行状态,出现active (running)说明启动成功
sudo systemctl status mysqld
# 5. 查看MySQL生成的初始root密码
sudo grep 'temporary password' /var/log/mysqld.log
# 6. 登录MySQL,输入上一步查到的初始密码
mysql -u root -p
# 7. 登录后,修改root用户的密码(必须先修改密码,才能执行其他操作)
ALTER USER 'root'@'localhost' IDENTIFIED BY '你的强密码@123';
# 8. (可选)开启root用户远程访问,允许其他机器连接该数据库
use mysql;
update user set host='%' where user='root';
flush privileges;
2.4 Docker环境安装(推荐,零污染本地环境)
Docker是现在开发人员最常用的环境部署方式,一键启动,不污染本地环境,随时可以重置,非常适合学习使用:
bash
# 1. 拉取MySQL 8.0官方镜像
docker pull mysql:8.0
# 2. 一键启动MySQL容器
# 参数说明:
# -d 后台运行
# --name 容器名称,自定义
# -p 端口映射,宿主机3306端口映射到容器3306端口
# -e MYSQL_ROOT_PASSWORD 设置root用户密码,必须设置
# -v 数据卷挂载,把容器内的数据、配置文件挂载到宿主机,避免容器删除后数据丢失
# --restart=always 开机自启
docker run -d \
--name mysql8 \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=你的强密码@123 \
-v /mysql/data:/var/lib/mysql \
-v /mysql/conf:/etc/mysql/conf.d \
--restart=always \
mysql:8.0
# 3. 验证容器是否运行成功,出现mysql8容器说明启动成功
docker ps | grep mysql8
# 4. 进入容器,登录MySQL命令行
docker exec -it mysql8 mysql -u root -p
2.5 客户端工具安装
MySQL服务端安装完成后,我们需要客户端工具来连接和操作数据库,这里推荐2款主流工具:
- DBeaver:开源免费、跨平台、功能强大,支持所有主流数据库,社区活跃度高,非常适合学习和开发使用,直接官网下载安装即可。
- Navicat Premium:界面友好,操作简单,功能全面,是企业最常用的数据库客户端,但是是付费软件,有14天免费试用期。
重要提醒:图形化工具只是辅助,一定要学会用原生命令行操作MySQL,因为线上生产环境绝大多数只有命令行,没有图形化工具。
第三章 筑基核心:彻底搞懂MySQL的核心概念与数据模型
很多人SQL写不好、面试被问懵,根源就是基础概念不清晰。这一章我们把MySQL的核心概念、数据类型、约束讲透,帮你打下最坚实的地基。
3.1 MySQL核心层级概念
我们用大家最熟悉的Excel来做类比,一秒搞懂MySQL的核心层级:
MySQL服务实例 → 数据库(Database) → 数据表(Table) → 列(Column/字段) + 行(Row/记录)
- MySQL服务实例:你安装启动的MySQL服务,一个服务器上可以运行多个实例,一个实例可以创建多个数据库
- 数据库 :相当于一个文件夹,用来分类管理数据表,比如一个电商系统,会创建
user_db(用户数据库)、order_db(订单数据库)、goods_db(商品数据库),实现数据的隔离管理 - 数据表 :相当于文件夹里的Excel文件,一个数据库里可以有多个表,每个表对应一类业务数据,比如
user表存储用户信息,order表存储订单信息 - 列(字段) :相当于Excel的表头,比如
user表里的id、username、phone、age,每个字段都有自己的数据类型和约束,定义了这个字段能存什么数据 - 行(记录):相当于Excel里的一行数据,也就是一条完整的业务记录,比如一个用户的信息,对应表中的一行数据
3.2 核心数据类型(建表的核心,90%的坑都在这里)
数据类型定义了字段能存储的数据格式、范围、存储空间,是建表的核心,选择合适的数据类型,不仅能保证数据的完整性,还能极大提升数据库的性能。
MySQL的数据类型主要分为三大类:数值类型、字符串类型、日期时间类型,我们只讲最常用、企业开发必用的类型,避开冷门无用的内容。
3.2.1 数值类型
分为整数类型、浮点/定点类型,核心原则:能存下数据的前提下,占用空间越小越好,存储空间越小,查询性能越高。
整数类型
| 类型 | 存储空间 | 有符号范围 | 无符号范围 | 核心适用场景 |
|---|---|---|---|---|
| TINYINT | 1字节 | -128~127 | 0~255 | 状态值、性别、年龄、枚举值,比如0-禁用/1-正常 |
| SMALLINT | 2字节 | -32768~32767 | 0~65535 | 小范围数字,比如商品分类ID、地区编码 |
| INT | 4字节 | -2147483648~2147483647 | 0~4294967295 | 绝大多数场景的业务ID、用户ID、订单ID |
| BIGINT | 8字节 | -9e18~9e18 | 0~1.8e19 | 超大规模主键、分布式雪花ID、大数据量表的主键 |
高频避坑点:
- 不要迷信
INT(11):MySQL8.0开始,INT后面的数字不代表存储长度,只代表显示宽度,没有任何实际意义,INT(1)和INT(11)的存储范围、占用空间完全一样,很多新手误以为INT(11)只能存11位数字,这是完全错误的。 - 不要用INT存小数字:比如年龄,最大不会超过150,用
TINYINT UNSIGNED完全足够,只占用1字节,用INT会浪费3字节,表数据量越大,浪费越严重,性能差距越明显。 - 主键优先用BIGINT:不要用INT当主键,很多公司都踩过数据量超过INT上限(21亿)导致的线上故障,BIGINT的上限几乎不可能达到,只多占用4字节,完全可以忽略。
- 无符号类型UNSIGNED:比如年龄、ID,不可能是负数,加上UNSIGNED可以扩大存储范围,避免负数的脏数据。
浮点/定点类型
| 类型 | 特点 | 适用场景 |
|---|---|---|
| FLOAT/DOUBLE | 浮点类型,占用空间小,但是存在精度丢失问题 | 非精准的数值计算,比如坐标、重量、温度等非财务数据 |
| DECIMAL(M,D) | 定点类型,精准存储,M是总位数,D是小数位数,最大M=65,D=30 | 金额、财务数据、需要精准计算的数值,比如商品价格、订单金额 |
致命避坑点 :金额绝对不能用FLOAT/DOUBLE存储! 因为浮点类型的二进制存储特性,会出现0.1 + 0.2 ≠ 0.3的精度问题,会直接导致财务数据错误,造成资金损失,这是生产环境的致命事故。金额必须用DECIMAL类型,比如DECIMAL(10,2),可以存储最大99999999.99的金额,完全满足绝大多数业务需求。
3.2.2 字符串类型
字符串类型是最常用的类型,核心分为定长字符串、变长字符串、大文本类型,这里重点讲面试必问、开发必用的CHAR和VARCHAR的核心区别。
| 类型 | 核心特点 | 最大长度 | 适用场景 |
|---|---|---|---|
| CHAR(M) | 定长字符串,M是字符数,不足M会自动补空格,查询效率极高 | 255字符 | 固定长度的内容,比如手机号(11位)、身份证号(18位)、性别编码、固定长度的唯一编码 |
| VARCHAR(M) | 变长字符串,M是最大字符数,只占用实际内容的存储空间,额外用1-2字节存储内容长度 | 65535字节,业务中建议不超过255 | 长度不固定的内容,比如用户名、地址、商品名称、备注信息 |
| TEXT | 大文本类型,分为TINYTEXT/TEXT/MEDIUMTEXT/LONGTEXT | 最大64KB(TEXT) | 长文本内容,比如文章详情、商品描述、富文本内容、日志信息 |
CHAR和VARCHAR的核心区别(面试必问,必须吃透):
- 存储方式不同 :
CHAR(11)无论你存1个字符还是11个字符,都会固定占用11个字符的存储空间,不足的部分会用空格补齐;而VARCHAR(11)存1个字符,只会占用1+1字节(1字节内容+1字节长度),只占用实际内容的空间。 - 查询性能不同:CHAR是定长存储,MySQL可以直接定位到数据的位置,查询效率比VARCHAR高很多;VARCHAR是变长存储,需要先读取长度,再定位数据,查询效率更低。
- 适用场景不同 :固定长度的内容,优先用CHAR,比如手机号固定11位,用
CHAR(11)比VARCHAR(11)性能更好,还能避免长度不一致的脏数据;长度不固定的内容,用VARCHAR,节省存储空间。
高频避坑点:
- VARCHAR(M)的M是字符数 ,不是字节数!比如
VARCHAR(20),可以存20个中文,也可以存20个英文,在utf8mb4字符集下,一个中文占4字节,所以M是字符数,不是字节数,很多新手在这里搞混。 - 不要用
VARCHAR(255)存所有内容:很多新手建表,所有字段都用VARCHAR(255),这是非常不规范的,合适的类型才是最好的,比如手机号用CHAR(11),性别用CHAR(1)。 - 非必要不要用TEXT类型:TEXT类型不能设置默认值,查询效率比VARCHAR低很多,还会占用额外的存储空间,短文本优先用VARCHAR,只有超过255字符的长文本才用TEXT。
- 不要用字符串存数值/日期:很多新手喜欢用VARCHAR存年龄、日期,这会导致无法使用数值/日期函数,查询时无法命中索引,性能极低,还会出现脏数据,必须用对应的类型存储。
3.2.3 日期时间类型
| 类型 | 存储空间 | 格式 | 范围 | 适用场景 |
|---|---|---|---|---|
| DATE | 3字节 | YYYY-MM-DD | 1000-01-01 ~ 9999-12-31 | 只需要日期,不需要时间,比如生日、入职日期、活动日期 |
| DATETIME | 5字节(8.0+) | YYYY-MM-DD HH:MM:SS | 1000-01-01 ~ 9999-12-31 | 绝大多数业务场景,创建时间、更新时间、操作时间,推荐优先使用 |
| TIMESTAMP | 4字节 | YYYY-MM-DD HH:MM:SS | 1970-01-01 ~ 2038-01-19 | 跨时区的业务场景,注意2038年溢出问题 |
高频避坑点:
- 优先用DATETIME,不要用TIMESTAMP:TIMESTAMP有2038年上限,到2038年就会溢出,很多老系统都踩过这个坑;MySQL8.0+的DATETIME只占用5字节,和TIMESTAMP的4字节差距极小,但是存储范围大得多,没有溢出风险。
- 不要用字符串存日期:很多新手用VARCHAR存日期,导致无法使用MySQL的日期函数,查询时无法命中索引,还会出现格式混乱的脏数据,必须用对应的日期类型。
- 自动维护时间:创建时间
create_time建议设置默认值DEFAULT CURRENT_TIMESTAMP,更新时间update_time设置DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,MySQL会自动维护这两个时间,不需要代码里处理,减少bug。
3.3 约束:保证数据完整性的核心
约束是定义在字段上的规则,用来限制存储在表中的数据,保证数据的完整性、一致性、有效性,避免脏数据进入数据库。零基础建表最容易忽略约束,导致后期出现大量脏数据,维护成本极高。
MySQL的核心约束有6种,我们逐个讲透用法和最佳实践:
- 主键约束 PRIMARY KEY
- 作用:唯一标识表中的一行数据,主键字段必须非空、唯一,一个表只能有一个主键
- 最佳实践:优先用
BIGINT AUTO_INCREMENT自增主键,不要用业务字段(比如手机号、身份证号)当主键,业务字段可能会变更,会导致严重的业务问题
- 非空约束 NOT NULL
- 作用:限制字段不能为空,必须赋值
- 最佳实践:除了特殊场景,所有字段都应该设置
NOT NULL,并配合DEFAULT设置默认值,因为NULL值会导致查询、索引失效,还会出现很多不可预期的查询结果,是MySQL的高频坑点
- 唯一约束 UNIQUE
- 作用:限制字段的值在表中必须唯一,不能重复,允许有NULL值(但NULL值也只能有一个)
- 适用场景:用户名、手机号、身份证号、订单编号等不能重复的业务字段
- 注意:唯一约束会自动创建唯一索引,提升查询效率
- 默认约束 DEFAULT
- 作用:给字段设置默认值,当插入数据没有给该字段赋值时,自动使用默认值
- 最佳实践:配合
NOT NULL使用,避免NULL值,比如性别默认0(未知),状态默认1(正常),创建时间默认当前时间
- 检查约束 CHECK
- 作用:检查字段的值是否符合指定的规则,不符合的话无法插入/更新
- 注意:MySQL8.0.16版本之后才正式支持CHECK约束,之前的版本虽然语法支持,但是不会生效,8.0+可以放心使用
- 示例:
age TINYINT CHECK (age > 0 AND age < 150),限制年龄必须在0-150之间
- 外键约束 FOREIGN KEY
- 作用:用来关联两个表,保证数据的一致性,比如订单表的
user_id关联用户表的id,保证订单对应的用户必须存在 - 重要提醒 :互联网企业的生产环境中,强烈不建议使用物理外键,而是用逻辑外键(代码里保证数据关联一致性)。原因:物理外键会导致锁冲突、性能下降、表之间耦合度极高,分布式场景下无法使用,批量导入数据时会有各种限制,维护成本极高。
- 作用:用来关联两个表,保证数据的一致性,比如订单表的
3.4 企业级建表最佳实践(零基础直接套用)
这里给大家一套企业开发中通用的建表规范,零基础可以直接套用,避免踩坑:
- 表必须有主键,优先使用
BIGINT NOT NULL AUTO_INCREMENT自增主键 - 所有字段尽量设置
NOT NULL + DEFAULT,避免NULL值 - 表必须有
create_time和update_time两个字段,自动维护时间 - 表名、字段名全部使用小写字母+下划线命名,禁止使用大写、中文、关键字,避免Linux下大小写敏感的问题
- 所有表、字段必须添加
COMMENT注释,说明用途,方便后续维护 - 选择合适的数据类型,遵循"最小够用"原则,避免大材小用
- 必须指定存储引擎为
InnoDB,字符集为utf8mb4,排序规则为utf8mb4_general_ci
第四章 SQL核心语法入门:DDL数据定义语言,学会建库建表
SQL(结构化查询语言)是操作关系型数据库的标准语言,主要分为四大类:
- DDL(数据定义语言) :用来操作数据库、表、索引等结构,关键字:
CREATE、ALTER、DROP、TRUNCATE - DML(数据操纵语言) :用来操作表中的数据,关键字:
INSERT、UPDATE、DELETE - DQL(数据查询语言) :用来查询数据,关键字:
SELECT,是SQL中最核心、最常用的部分 - DCL(数据控制语言) :用来管理用户、权限,关键字:
GRANT、REVOKE、CREATE USER
这一章我们先讲DDL语言,先有库和表,才能操作数据。
4.1 数据库的常用操作
sql
-- =============================================
-- 1. 创建数据库(核心,必须掌握)
-- 注意:必须指定utf8mb4字符集,不要用utf8,MySQL的utf8是伪utf8,最多存3字节,不支持emoji和生僻字
-- IF NOT EXISTS:如果数据库不存在才创建,避免重复创建报错
-- DEFAULT CHARACTER SET:指定默认字符集
-- DEFAULT COLLATE:指定默认排序规则
-- =============================================
CREATE DATABASE IF NOT EXISTS user_db
DEFAULT CHARACTER SET utf8mb4
DEFAULT COLLATE utf8mb4_general_ci;
-- 2. 查看MySQL实例中所有的数据库
SHOW DATABASES;
-- 3. 切换/使用数据库,后续的表操作都会在这个数据库中执行
USE user_db;
-- 4. 查看当前正在使用的数据库
SELECT DATABASE();
-- 5. 修改数据库的字符集(一般不修改,创建时就指定好)
ALTER DATABASE user_db DEFAULT CHARACTER SET utf8mb4;
-- 6. 删除数据库(高危操作!!!生产环境绝对禁止执行)
-- IF EXISTS:如果数据库存在才删除,避免报错
DROP DATABASE IF EXISTS user_db;
4.2 表的常用操作
4.2.1 创建表(核心,企业级规范示例)
我们基于上面的建表最佳实践,创建一个规范的系统用户表,逐行带注释,零基础可以直接套用:
sql
-- 创建系统用户表,完全符合企业级开发规范
CREATE TABLE IF NOT EXISTS sys_user (
id BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
username VARCHAR(50) NOT NULL COMMENT '用户名,登录账号',
password VARCHAR(100) NOT NULL COMMENT '密码,加密存储,禁止明文',
phone CHAR(11) NOT NULL COMMENT '手机号',
age TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '年龄',
gender CHAR(1) NOT NULL DEFAULT '0' COMMENT '性别:0-未知,1-男,2-女',
email VARCHAR(100) DEFAULT NULL COMMENT '邮箱',
birthday DATE DEFAULT NULL COMMENT '生日',
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态:0-禁用,1-正常',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-- 主键约束
PRIMARY KEY (id),
-- 唯一约束,保证用户名和手机号不重复
UNIQUE KEY uk_username (username),
UNIQUE KEY uk_phone (phone),
-- 普通索引,提升查询效率,后续进阶篇会详细讲解索引
KEY idx_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统用户表';
4.2.2 表的查看操作
sql
-- 1. 查看当前数据库下的所有表
SHOW TABLES;
-- 2. 查看表的结构,字段名、类型、约束等信息
DESC sys_user;
-- 3. 查看表的完整创建语句,包括注释、索引、字符集、存储引擎等所有信息
SHOW CREATE TABLE sys_user;
4.2.3 表的修改操作(ALTER TABLE)
开发中经常需要修改表结构,比如加字段、改字段、加索引,这里讲最常用的操作:
sql
-- 1. 给表添加字段
-- 示例:给sys_user表添加address地址字段,加到email字段后面
-- AFTER:指定字段的位置,不加的话默认加到表的最后
ALTER TABLE sys_user
ADD COLUMN address VARCHAR(200) NOT NULL DEFAULT '' COMMENT '地址' AFTER email;
-- 2. 修改字段的类型、约束、默认值、注释
-- 示例:修改age字段的默认值为18
ALTER TABLE sys_user
MODIFY COLUMN age TINYINT UNSIGNED NOT NULL DEFAULT 18 COMMENT '年龄';
-- 3. 修改字段名(尽量不要修改,会影响业务代码)
-- 示例:把gender字段名改成sex
ALTER TABLE sys_user
CHANGE COLUMN gender sex CHAR(1) NOT NULL DEFAULT '0' COMMENT '性别:0-未知,1-男,2-女';
-- 4. 删除字段(高危操作,生产环境谨慎执行)
ALTER TABLE sys_user DROP COLUMN address;
-- 5. 修改表名(尽量不要修改,影响极大)
ALTER TABLE sys_user RENAME TO sys_user_info;
-- 6. 给表添加索引
-- 示例:给email字段添加唯一索引
ALTER TABLE sys_user ADD UNIQUE KEY uk_email (email);
-- 7. 删除索引
ALTER TABLE sys_user DROP INDEX uk_email;
4.2.4 表的删除/清空操作(高危操作,必须警惕)
sql
-- 1. 删除表,表结构和数据全部删除,无法恢复(生产环境绝对禁止执行)
DROP TABLE IF EXISTS sys_user;
-- 2. 清空表数据,保留表结构,自增主键重置,执行速度极快(高危操作!!!)
TRUNCATE TABLE sys_user;
重要提醒 :TRUNCATE是DDL操作,不是DML操作,不会触发事务,无法回滚,执行后数据直接清空,无法恢复;而DELETE是DML操作,在事务中可以回滚,这是两者的核心区别,面试必问。
第五章 SQL核心语法:DML数据操纵语言,学会增删改数据
DML是用来操作表中数据的语言,核心就是增、删、改,是业务开发中最常用的语法,同时也是生产环境事故最高发的部分,必须吃透,避开高危坑点。
5.1 INSERT 插入数据
sql
-- =============================================
-- 1. 插入单行数据(推荐写法)
-- 优点:指定字段,不依赖表的字段顺序,表结构变更不会导致插入报错
-- 注意:字段顺序和VALUES里的值顺序必须一一对应,类型匹配
-- =============================================
INSERT INTO sys_user (username, password, phone, age, gender, email, birthday, status)
VALUES ('zhangsan', 'e10adc3949ba59abbe56e057f20f883e', '13800138000', 25, '1', 'zhangsan@example.com', '2000-01-01', 1);
-- 2. 插入单行数据(不推荐写法)
-- 不指定字段,必须按表的字段顺序赋值,表结构变了就会报错,维护性极差
INSERT INTO sys_user
VALUES (2, 'lisi', 'e10adc3949ba59abbe56e057f20f883e', '13800138001', 23, '2', 'lisi@example.com', '2001-02-02', 1, NOW(), NOW());
-- =============================================
-- 3. 批量插入数据(强烈推荐,业务开发必用)
-- 优点:一次插入多条数据,性能比多次单行插入高10倍以上,减少数据库IO压力
-- =============================================
INSERT INTO sys_user (username, password, phone, age, gender, email, birthday, status)
VALUES
('wangwu', 'e10adc3949ba59abbe56e057f20f883e', '13800138002', 28, '1', 'wangwu@example.com', '1997-03-03', 1),
('zhaoliu', 'e10adc3949ba59abbe56e057f20f883e', '13800138003', 22, '2', 'zhaoliu@example.com', '1999-04-04', 1),
('qianqi', 'e10adc3949ba59abbe56e057f20f883e', '13800138004', 30, '1', 'qianqi@example.com', '1995-05-05', 0);
-- =============================================
-- 4. 存在则更新,不存在则插入(业务高频场景)
-- 基于唯一键(主键/唯一约束)实现,避免重复插入数据,比如导入数据、用户注册
-- =============================================
INSERT INTO sys_user (username, password, phone, age, gender)
VALUES ('zhangsan', 'new_password123', '13800138000', 26, '1')
ON DUPLICATE KEY UPDATE
password = VALUES(password),
age = VALUES(age),
update_time = CURRENT_TIMESTAMP;
5.2 UPDATE 更新数据(高危操作,必须警惕)
生产环境第一大事故:忘写WHERE条件的UPDATE,导致全表数据被更新! 必须严格遵守"先查后改"的原则,执行UPDATE之前,先执行SELECT确认WHERE条件能查到的行数,避免误操作。
sql
-- 1. 更新单行数据(推荐写法,必须加WHERE条件)
UPDATE sys_user
SET age = 26, email = 'zhangsan_new@example.com'
WHERE id = 1;
-- 2. 批量更新数据,符合WHERE条件的所有行都会被更新
UPDATE sys_user
SET status = 0
WHERE age > 28;
-- 3. 高危操作!!!没有WHERE条件,会更新全表的所有数据,生产环境绝对禁止执行
-- UPDATE sys_user SET status = 0;
-- 避坑技巧:更新前先执行SELECT,确认WHERE条件的结果
-- 比如先执行 SELECT * FROM sys_user WHERE id = 1; 确认数据正确,再执行UPDATE
5.3 DELETE 删除数据(高危操作,必须警惕)
和UPDATE一样,忘写WHERE条件的DELETE,会导致全表数据被删除,是生产环境第二大事故,必须严格遵守"先查后删"的原则。
sql
-- 1. 删除单行数据(推荐写法,必须加WHERE条件)
DELETE FROM sys_user
WHERE id = 5;
-- 2. 批量删除数据,符合WHERE条件的所有行都会被删除
DELETE FROM sys_user
WHERE status = 0 AND create_time < '2024-01-01';
-- 3. 高危操作!!!没有WHERE条件,会删除全表的所有数据,生产环境绝对禁止执行
-- DELETE FROM sys_user;
-- 避坑技巧:删除前先执行SELECT,确认WHERE条件的结果
-- 比如先执行 SELECT * FROM sys_user WHERE id = 5; 确认数据正确,再执行DELETE
第六章 SQL核心语法:DQL数据查询语言(基础篇),单表查询全解
DQL(数据查询语言)是SQL中最核心、最常用的部分,业务开发中90%的SQL语句都是查询语句,也是面试的重中之重。本篇我们先讲单表查询,多表关联查询放在中篇详细讲解。
6.1 DQL完整语法与执行顺序(核心中的核心,必须吃透)
很多人写SQL逻辑混乱、报错,根源就是不知道SQL的语法顺序和执行顺序,这里先给大家讲透,理解了这个,你就能写出逻辑清晰的SQL。
sql
-- =====================
-- 1. 语法顺序(写SQL的时候,必须严格按照这个顺序写,否则会报错)
-- =====================
SELECT 字段列表
FROM 表名
[WHERE 条件过滤]
[GROUP BY 分组字段]
[HAVING 分组后过滤]
[ORDER BY 排序字段 排序规则]
[LIMIT 分页限制];
-- =====================
-- 2. 执行顺序(MySQL实际执行SQL的顺序,非常重要!!!)
-- =====================
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT
核心解读:
- MySQL先从
FROM指定的表中获取数据,然后用WHERE过滤掉不符合条件的数据 - 把过滤后的数据用
GROUP BY进行分组,然后用HAVING过滤掉不符合条件的分组 - 然后执行
SELECT查询指定的字段,去重、计算等操作 - 再用
ORDER BY对结果进行排序,最后用LIMIT限制返回的行数 - 这就是为什么
WHERE里不能用聚合函数,因为WHERE的执行顺序在SELECT之前,还没计算聚合结果;而HAVING在GROUP BY之后,可以用聚合函数
6.2 基础查询
sql
-- =============================================
-- 1. 查询指定字段(强烈推荐,生产环境规范)
-- 只查询业务需要的字段,不要查询多余的字段,提升性能,支持覆盖索引
-- =============================================
SELECT id, username, phone, age, status FROM sys_user;
-- 2. 查询所有字段(绝对禁止在生产环境使用SELECT *)
-- 缺点:查询多余字段,增加网络传输开销,无法使用覆盖索引,表结构变更会导致代码报错
SELECT * FROM sys_user;
-- 3. 给字段起别名,AS可以省略,别名有空格时必须加引号
SELECT
id AS '用户ID',
username '用户名',
phone '手机号',
age '年龄'
FROM sys_user;
-- 4. 查询去重的数据,DISTINCT,比如查询所有不重复的年龄
SELECT DISTINCT age FROM sys_user;
-- 5. 字段运算,比如根据年龄计算出生年份
SELECT
username,
age,
YEAR(NOW()) - age AS '出生年份'
FROM sys_user;
6.3 WHERE 条件过滤查询
WHERE子句用来过滤数据,只返回符合条件的记录,是查询中最常用的子句。
6.3.1 常用条件运算符
- 比较运算符:
=、!=/<>、>、<、>=、<=、BETWEEN ... AND、IN、IS NULL、IS NOT NULL - 逻辑运算符:
AND、OR、NOT
6.3.2 代码示例
sql
-- 1. 等值查询,查询id=1的用户
SELECT id, username, phone FROM sys_user WHERE id = 1;
-- 2. 不等值查询,查询状态不是正常的用户
SELECT id, username, status FROM sys_user WHERE status != 1;
-- 等价于 <>,和!=效果完全一致
SELECT id, username, status FROM sys_user WHERE status <> 1;
-- 3. 范围查询,查询年龄在20到30之间的用户
-- BETWEEN ... AND 是闭区间,包含边界值20和30
SELECT id, username, age FROM sys_user WHERE age BETWEEN 20 AND 30;
-- 等价于
SELECT id, username, age FROM sys_user WHERE age >= 20 AND age <= 30;
-- 4. IN枚举查询,查询年龄是22、25、28的用户
SELECT id, username, age FROM sys_user WHERE age IN (22,25,28);
-- 等价于
SELECT id, username, age FROM sys_user WHERE age =22 OR age=25 OR age=28;
-- 5. NULL值查询,查询邮箱为空的用户
-- 注意:NULL不能用=判断,必须用IS NULL,因为NULL和任何值比较都是NULL,不会返回true
SELECT id, username, email FROM sys_user WHERE email IS NULL;
-- 查询邮箱不为空的用户
SELECT id, username, email FROM sys_user WHERE email IS NOT NULL;
-- 6. 逻辑运算符AND,多个条件必须同时满足
-- 查询年龄大于20、状态正常的女性用户
SELECT id, username, age, gender, status FROM sys_user
WHERE age > 20 AND gender = '2' AND status = 1;
-- 7. 逻辑运算符OR,多个条件满足一个即可
-- 查询年龄小于20或者大于30的用户
SELECT id, username, age FROM sys_user WHERE age < 20 OR age > 30;
-- 8. 模糊查询LIKE
-- % 匹配任意多个字符(0个或多个),_ 匹配单个字符
-- 查询用户名以zhang开头的用户
SELECT id, username FROM sys_user WHERE username LIKE 'zhang%';
-- 查询用户名包含san的用户
SELECT id, username FROM sys_user WHERE username LIKE '%san%';
-- 查询用户名第二个字符是h的用户
SELECT id, username FROM sys_user WHERE username LIKE '_h%';
高频避坑点:
AND的优先级高于OR,多条件混合使用时,必须用括号明确优先级,比如WHERE (a=1 OR b=2) AND c=3,不要写成WHERE a=1 OR b=2 AND c=3,会导致逻辑错误%开头的模糊查询,会导致索引失效,数据量大的时候查询性能极差,后续进阶篇会详细讲解- 不要在WHERE子句中对字段进行函数运算,比如
WHERE YEAR(create_time) = 2024,会导致索引失效,应该写成WHERE create_time BETWEEN '2024-01-01' AND '2024-12-31'
6.4 聚合函数查询
聚合函数用来对一组数据进行统计计算,返回一个结果,常用在数据统计、分组查询中。
常用聚合函数:
| 函数 | 作用 |
|---|---|
| COUNT() | 统计行数 |
| SUM() | 计算数值的和 |
| AVG() | 计算数值的平均值 |
| MAX() | 计算最大值 |
| MIN() | 计算最小值 |
代码示例:
sql
-- 1. COUNT() 统计行数,最常用
-- 统计表中的总用户数,推荐写法,COUNT(1)和COUNT(*)效果一致,MySQL8.0做了优化,性能几乎无差别
SELECT COUNT(1) AS '总用户数' FROM sys_user;
-- 统计状态正常的用户数
SELECT COUNT(1) AS '正常用户数' FROM sys_user WHERE status = 1;
-- 统计有邮箱的用户数,COUNT(字段)会忽略NULL值
SELECT COUNT(email) AS '有邮箱的用户数' FROM sys_user;
-- 2. SUM() 求和,统计所有用户的年龄总和
SELECT SUM(age) AS '年龄总和' FROM sys_user;
-- 3. AVG() 求平均值,统计所有用户的平均年龄
SELECT AVG(age) AS '平均年龄' FROM sys_user;
-- 4. MAX() 求最大值,统计最大的年龄
SELECT MAX(age) AS '最大年龄' FROM sys_user;
-- 5. MIN() 求最小值,统计最小的年龄
SELECT MIN(age) AS '最小年龄' FROM sys_user;
-- 6. 组合使用,多个聚合函数一起查询
SELECT
COUNT(1) AS '总用户数',
MAX(age) AS '最大年龄',
MIN(age) AS '最小年龄',
AVG(age) AS '平均年龄',
SUM(age) AS '年龄总和'
FROM sys_user WHERE status = 1;
高频避坑点:
- 所有聚合函数都会忽略NULL值,比如
AVG(age),如果age有NULL值,会忽略这些行,不会计入平均值的计算 - 不要用
COUNT(可能为NULL的字段)来统计总行数,会导致统计结果错误,应该用COUNT(*)或COUNT(1) - 聚合函数不能用在WHERE子句中,因为WHERE的执行顺序在SELECT之前,还没计算聚合结果,会直接报错,必须用HAVING子句
6.5 GROUP BY 分组查询
GROUP BY子句用来把数据按照指定的字段进行分组,配合聚合函数使用,实现分组统计,比如按性别统计用户数,按状态统计订单数。
sql
-- 1. 按性别分组,统计不同性别的用户数
SELECT
gender AS '性别',
COUNT(1) AS '用户数'
FROM sys_user
GROUP BY gender;
-- 2. 按状态分组,统计不同状态的用户数、平均年龄
SELECT
status AS '状态',
COUNT(1) AS '用户数',
AVG(age) AS '平均年龄'
FROM sys_user
GROUP BY status;
-- 3. 多字段分组,先按状态分组,状态相同的再按性别分组
SELECT
status AS '状态',
gender AS '性别',
COUNT(1) AS '用户数'
FROM sys_user
GROUP BY status, gender;
重要提醒 :MySQL5.7+默认开启ONLY_FULL_GROUP_BY模式,GROUP BY的字段,必须出现在SELECT的字段中(聚合函数除外),否则会直接报错,这是SQL的规范,必须遵守。
6.6 HAVING 分组后过滤
HAVING子句用来对分组后的结果进行过滤,和WHERE的核心区别:
- WHERE:分组前过滤,对原始数据进行过滤,不能使用聚合函数
- HAVING:分组后过滤,对分组统计后的结果进行过滤,可以使用聚合函数
sql
-- 统计用户数大于2的年龄分组
SELECT
age,
COUNT(1) AS '用户数'
FROM sys_user
GROUP BY age
HAVING COUNT(1) > 2;
-- 错误写法:WHERE中不能使用聚合函数
-- SELECT age, COUNT(1) AS '用户数' FROM sys_user WHERE COUNT(1) >2 GROUP BY age;
-- 组合使用WHERE和HAVING,先过滤,再分组,再过滤
-- 先过滤状态正常的用户,按性别分组,再过滤用户数大于1的分组
SELECT
gender,
COUNT(1) AS '用户数'
FROM sys_user
WHERE status = 1
GROUP BY gender
HAVING COUNT(1) > 1;
6.7 ORDER BY 排序查询
ORDER BY子句用来对查询结果进行排序,ASC为升序(默认),DESC为降序。
sql
-- 1. 按年龄升序排序,ASC可以省略,默认升序
SELECT id, username, age FROM sys_user ORDER BY age ASC;
-- 等价于
SELECT id, username, age FROM sys_user ORDER BY age;
-- 2. 按年龄降序排序
SELECT id, username, age FROM sys_user ORDER BY age DESC;
-- 3. 多字段排序,先按年龄降序,年龄相同的按id升序
SELECT id, username, age, create_time FROM sys_user ORDER BY age DESC, id ASC;
-- 4. 配合WHERE使用,先过滤再排序
SELECT id, username, age FROM sys_user WHERE status =1 ORDER BY age DESC;
6.8 LIMIT 分页查询
LIMIT子句用来限制查询结果返回的行数,是业务开发中分页功能的核心实现方式。
语法:LIMIT offset, size,其中offset是偏移量,从0开始,size是每页返回的条数。
sql
-- 1. 分页查询,第1页,每页2条数据
SELECT id, username, age FROM sys_user ORDER BY id DESC LIMIT 0, 2;
-- 2. 第2页,每页2条数据
SELECT id, username, age FROM sys_user ORDER BY id DESC LIMIT 2, 2;
-- 3. 简写,只查询前N条数据,LIMIT N 等价于 LIMIT 0,N
SELECT id, username FROM sys_user LIMIT 3;
分页公式 :第page页,每页size条数据,LIMIT (page-1)*size, size
避坑点 :offset越大,分页性能越差,比如LIMIT 100000, 10,需要扫描100010条数据,性能极差,后续精通篇会详细讲解深分页的优化方案。
第七章 SQL基础权限管理:DCL数据控制语言
DCL(数据控制语言)用来管理MySQL的用户、权限,生产环境中,绝对不会用root用户直接操作业务,都是创建专用的业务用户,分配最小权限,保证数据库的安全。
sql
-- 1. 创建用户
-- 格式:CREATE USER '用户名'@'访问主机' IDENTIFIED BY '密码';
-- 访问主机:% 表示所有主机都可以访问,localhost 只能本地访问,也可以指定固定IP/IP段
CREATE USER 'app_user'@'%' IDENTIFIED BY 'AppUser@123456';
-- 2. 给用户授权
-- 格式:GRANT 权限列表 ON 数据库.表 TO '用户名'@'访问主机';
-- 给app_user用户授予user_db库下所有表的查询、插入、更新、删除权限(业务常用)
GRANT SELECT, INSERT, UPDATE, DELETE ON user_db.* TO 'app_user'@'%';
-- 给用户授予所有权限(不推荐,生产环境绝对禁止)
-- GRANT ALL PRIVILEGES ON *.* TO 'app_user'@'%';
-- 3. 刷新权限,授权/撤销权限后必须执行,否则不生效
FLUSH PRIVILEGES;
-- 4. 查看用户的权限
SHOW GRANTS FOR 'app_user'@'%';
-- 5. 撤销用户的权限
REVOKE DELETE ON user_db.* FROM 'app_user'@'%';
FLUSH PRIVILEGES;
-- 6. 修改用户密码
ALTER USER 'app_user'@'%' IDENTIFIED BY 'NewAppUser@123456';
FLUSH PRIVILEGES;
-- 7. 删除用户
DROP USER 'app_user'@'%';
生产环境权限最佳实践:
- 最小权限原则:只给用户需要的权限,不要给ALL PRIVILEGES,业务用户一般只给SELECT、INSERT、UPDATE、DELETE权限
- 限制访问主机:不要用%,尽量指定固定的IP段,比如'192.168.1.%',提升安全性
- 强密码策略:密码必须包含大小写、数字、特殊字符,长度不低于8位,定期更换
- 禁止业务代码用root用户连接数据库,root用户只用于数据库管理
- 不同的业务系统,创建不同的用户,只分配对应数据库的权限,实现权限隔离
第八章 零基础必看:本篇最佳实践与避坑指南
8.1 建库建表规范
- 数据库必须使用
utf8mb4字符集,不要用utf8,避免emoji和生僻字存储报错 - 表必须有主键,优先使用
BIGINT AUTO_INCREMENT自增主键,不要用业务字段当主键 - 所有字段尽量设置
NOT NULL + DEFAULT,避免NULL值带来的索引失效、查询异常问题 - 表必须有
create_time和update_time字段,自动维护时间,不需要代码处理 - 表名、字段名全部使用小写字母+下划线,禁止使用大写、中文、关键字,避免跨平台大小写问题
- 所有表、字段必须添加COMMENT注释,方便后续维护
- 遵循"最小够用"原则,选择合适的数据类型,越小的类型,性能越好
- 金额必须用
DECIMAL类型,绝对不能用FLOAT/DOUBLE,避免精度丢失 - 日期必须用
DATETIME/DATE类型,不要用字符串存储,避免无法使用日期函数和索引
8.2 SQL编写规范
- 绝对禁止使用
SELECT *,只查询业务需要的字段 - UPDATE、DELETE语句必须加WHERE条件,执行前先SELECT确认,避免全表更新/删除
- 避免使用%开头的模糊查询,会导致索引失效
- 批量插入优先使用
INSERT ... VALUES (...), (...),不要多次单行插入,提升性能 - WHERE条件中,不要对字段进行函数运算,会导致索引失效
- 多条件查询,AND优先级高于OR,用括号明确优先级,避免逻辑错误
- 不要在业务代码中使用DDL语句,比如ALTER、DROP、TRUNCATE
8.3 安全规范
- 生产环境禁止用root用户操作业务,创建专用业务用户,遵循最小权限原则
- 限制数据库访问IP,不要开放给所有主机
- 密码必须强复杂度,定期更换,禁止在代码中硬编码数据库密码
- 生产环境禁止执行DROP、TRUNCATE等高危操作,必须有审批流程
- 数据库必须定期备份,避免数据丢失
本篇总结与下篇预告
本篇总结
学完本篇,你已经完成了MySQL的筑基,彻底摆脱了SQL小白的身份:
- 了解了MySQL的核心定位与架构,掌握了全场景的环境搭建
- 彻底搞懂了MySQL的核心概念、数据类型、约束,掌握了企业级建库建表规范
- 熟练掌握了DDL数据定义语言,能独立完成库、表的创建、修改、删除
- 熟练掌握了DML数据操纵语言,能完成数据的增、删、改,避开了高危操作的坑
- 熟练掌握了DQL单表查询的全语法,理解了SQL的执行顺序,能写出逻辑清晰的查询语句
- 掌握了DCL权限管理,能创建用户、分配权限,符合生产安全规范
下篇预告
《零基础从入门到精通MySQL(中篇):进阶篇------吃透多表查询、事务与高级特性,搞定复杂业务SQL》
在下篇中,我们将深入讲解:
- 多表关联查询:INNER JOIN、LEFT JOIN、RIGHT JOIN的用法与核心区别,搞定复杂业务的关联查询
- 子查询、临时表、公用表表达式CTE的用法与最佳实践
- 视图、存储过程、自定义函数、触发器的使用与避坑指南
- 事务的核心原理、ACID特性、隔离级别,彻底搞懂并发数据一致性问题
- InnoDB存储引擎的核心特性,与MyISAM的核心区别
互动环节
如果你在学习过程中遇到任何问题,或者有想了解的知识点,欢迎在评论区留言,我会一一回复。
如果本篇内容对你有帮助,欢迎点赞、收藏、转发,关注我,后续的中篇、下篇、八股文附加篇会第一时间更新,带你一步步吃透MySQL,从入门到精通!