作为全球最流行的开源关系型数据库,MySQL 凭借轻量、高效、易扩展的特性,成为后端开发、数据分析等领域的必备工具。本文针对零基础到进阶开发者,从环境搭建到复杂查询,系统梳理 MySQL 核心用法,每个知识点配套实战代码与避坑指南,帮你快速上手并解决实际业务问题。建议收藏本文,后续可随时查阅实战细节。
一、入门篇:MySQL 环境搭建与基础连接
1.1 环境搭建(Windows/Linux 通用)
1.1.1 下载与安装
- 官方地址:MySQL Community Server(选择对应系统版本,推荐 8.0+,兼容性与安全性更优)
- Windows 安装注意事项:
安装时选择「Custom」模式,仅勾选「MySQL Server」和「MySQL Workbench」(可视化工具),避免安装冗余组件;
设置 root 密码时需包含大小写字母、数字与特殊符号(如Root@1234),符合 MySQL 8.0 + 的密码强度策略。
- Linux(CentOS 7)安装命令:
# 1. 安装MySQL官方仓库(解决yum源无最新版本问题)
# 1. 安装MySQL官方仓库(解决yum源无最新版本问题)
wget https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm
rpm -ivh mysql80-community-release-el7-3.noarch.rpm
# 2. 安装MySQL服务(自动处理依赖)
yum install -y mysql-community-server
# 3. 启动服务并设置开机自启
systemctl start mysqld
systemctl enable mysqld
# 4. 查看初始密码(首次登录必须使用,后续需修改)
grep 'temporary password' /var/log/mysqld.log
1.1.2 三种连接方式(适配不同场景)
- 命令行连接(服务器端操作首选):
# 本地连接(默认3306端口)
mysql -u root -p
# 远程连接(需先开启root远程访问权限)
mysql -h 192.168.1.100 -u root -p -P 3306
🔧 开启远程访问权限(首次登录后执行):
use mysql;
update user set host = '%' where user = 'root';
flush privileges; -- 刷新权限生效(生产环境建议限制IP,而非允许任意IP)
- MySQL Workbench 连接(可视化操作,适合新手):
打开软件 → 点击「+」新建连接 → 填写:
-
- Connection Name:自定义(如 “本地 MySQL”)
-
- Hostname:本地填localhost,远程填服务器 IP
-
- Username:root
-
- Password:点击「Store in Vault」保存密码
点击「Test Connection」,提示 “Success” 后点击「OK」完成创建。
- Python 连接(开发项目必备):
先安装依赖库:pip install pymysql
import pymysql
from pymysql import OperationalError
def connect_mysql():
try:
# 建立数据库连接(charset必须为utf8mb4,支持中文与表情)
conn = pymysql.connect(
host='localhost',
user='root',
password='Root@1234',
database='test_db', # 需提前创建,否则报错
port=3306,
charset='utf8mb4',
cursorclass=pymysql.cursors.DictCursor # 游标返回字典(可读性更高)
)
print("MySQL连接成功!")
return conn
except OperationalError as e:
print(f"连接失败:{e}") # 捕获密码错误、数据库不存在等常见问题
return None
# 调用连接函数并关闭资源
conn = connect_mysql()
if conn:
conn.close()
二、基础篇:数据库与表的核心操作(DDL/DML)
2.1 数据库操作(DDL)
-- 1. 查看所有数据库
show databases;
-- 2. 创建数据库(指定字符集,避免中文乱码)
create database if not exists test_db
character set utf8mb4
collate utf8mb4_general_ci; -- 排序规则,通用选择utf8mb4_general_ci
-- 3. 切换到目标数据库
use test_db;
-- 4. 查看当前所在数据库
select database();
-- 5. 删除数据库(谨慎!不可逆,建议先备份)
drop database if exists test_db;
2.2 数据表操作(DDL)
以业务常用的「用户表(user)」为例,设计包含id(主键)、username(用户名)、age(年龄)等字段的表结构。
2.2.1 创建表(含约束与最佳实践)
create table if not exists user (
id int primary key auto_increment comment '用户ID(主键,自增)',
username varchar(50) not null unique comment '用户名(非空且唯一,避免重复注册)',
age tinyint check (age > 0 and age < 150) comment '年龄(1-149岁,符合实际场景)',
email varchar(100) unique comment '邮箱(唯一,用于登录与通知)',
create_time datetime default current_timestamp comment '创建时间(默认当前时间)'
) engine=InnoDB default charset=utf8mb4 comment '用户表';
✨ 关键参数解析:
- engine=InnoDB:默认存储引擎,支持事务、外键与行级锁,适合业务表;
- auto_increment:主键自增,避免手动赋值导致重复;
- comment:字段与表的注释,便于团队协作(生产环境必须添加)。
2.2.2 表结构修改与管理
-- 1. 查看当前数据库所有表
show tables;
-- 2. 查看表结构(简洁版/详细版)
desc user; -- 简洁版(字段名、类型、约束)
show create table user; -- 详细版(含索引、注释)
-- 3. 添加字段(新增「phone」手机号字段)
alter table user
add column phone char(11) unique comment '手机号'
after email; -- after指定位置,默认加在最后
-- 4. 修改字段(将「age」从tinyint改为int)
alter table user
modify column age int comment '年龄(修改后支持更大范围)';
-- 5. 删除字段(谨慎!数据不可逆)
alter table user drop column phone;
-- 6. 删除表(彻底删除表结构与数据,生产环境禁止随意执行)
drop table if exists user;
2.3 数据操纵(DML:增删改)
2.3.1 插入数据(INSERT)
-- 1. 插入单条数据(指定字段,推荐!避免字段顺序变化导致错误)
insert into user (username, age, email)
values ('zhangsan', 25, 'zhangsan@xxx.com');
-- 2. 批量插入(减少IO操作,效率比单条插入高10倍以上)
insert into user (username, age, email)
values
('lisi', 30, 'lisi@xxx.com'),
('wangwu', 28, 'wangwu@xxx.com'),
('zhaoliu', 35, 'zhaoliu@xxx.com');
-- 3. 插入后获取自增ID(适用于插入后需用ID做后续操作,如关联订单)
select last_insert_id();
2.3.2 更新数据(UPDATE)
-- 1. 单条件更新(修改指定用户的年龄)
update user set age = 31 where username = 'lisi';
-- 2. 多条件更新(精准定位,避免误改数据)
update user
set email = 'wangwu_new@xxx.com'
where id = 3 and email = 'wangwu@xxx.com';
-- 3. 批量更新(用case when,减少SQL请求次数)
update user
set age = case username
when 'zhangsan' then 26 -- 张三年龄改为26
when 'lisi' then 32 -- 李四年龄改为32
when 'zhaoliu' then 36 -- 赵六年龄改为36
else age -- 其他用户保持原年龄(必须加,否则未匹配用户年龄设为NULL)
end
where username in ('zhangsan', 'lisi', 'zhaoliu');
⚠️ 致命误区:UPDATE语句必须加where条件!若省略,会修改表中所有数据,生产环境需严格审核。
2.3.3 删除数据(DELETE/TRUNCATE)
-- 1. 条件删除(DELETE,支持事务回滚,适合删除部分数据)
delete from user where username = 'wangwu';
-- 2. 清空表数据(TRUNCATE,不可回滚,速度比DELETE快)
truncate table user;
特性 |
DELETE |
TRUNCATE |
数据恢复 |
支持事务回滚 |
不可回滚(直接清空数据页) |
自增 ID |
不重置(继续从上次自增) |
重置为 1 |
执行速度 |
慢(逐行删除,写日志) |
快(直接删除表数据页) |
适用场景 |
删除部分数据 |
清空全表 |
三、进阶篇:复杂查询与索引优化(上)
3.1 基础查询(DQL)
-- 1. 查询指定字段(避免用*,减少网络传输与内存占用)
select id, username, age from user;
-- 2. 字段别名(AS可省略,提升结果可读性)
select
id as '用户ID',
username '用户名', -- 省略AS
age '年龄'
from user;
-- 3. 条件查询(where + 逻辑运算符)
-- 示例:查询25-35岁、用户名含「zhang」且邮箱非空的用户
select * from user
where age between 25 and 35
and username like '%zhang%'
and email is not null;
-- 4. 去重查询(distinct,统计不重复的年龄)
select distinct age from user;
-- 5. 排序(order by,asc升序/desc降序,默认asc)
-- 示例:按年龄降序,年龄相同按创建时间升序
select * from user order by age desc, create_time asc;
-- 6. 分页查询(limit,避免一次性查大量数据导致内存溢出)
-- 语法:limit 起始索引, 每页条数(起始索引 = (页码-1)* 每页条数)
-- 示例:查询第2页数据,每页2条(页码=2,每页条数=2)
select * from user limit 2, 2;
3.2 复杂查询(多表关联 / 聚合函数)
3.2.1 准备关联表数据
假设新增「订单表(order)」,与用户表通过user_id关联:
create table if not exists `order` ( -- order是关键字,需用反引号包裹
order_id int primary key auto_increment comment '订单ID',
user_id int not null comment '关联用户ID',
order_amount decimal(10,2) not null comment '订单金额',
order_time datetime default current_timestamp comment '下单时间',
-- 外键约束(保证数据一致性,删除用户时自动删除关联订单)
foreign key (user_id) references user(id) on delete cascade
) engine=InnoDB default charset=utf8mb4 comment '订单表';
-- 插入测试数据
insert into `order` (user_id, order_amount)
values (1, 99.9), (1, 199.5), (2, 299.0), (3, 499.9);
3.2.2 常用 JOIN 场景示例
- 左连接(LEFT JOIN):查询所有用户,包括无订单的用户(如统计用户下单率)
select
u.username '用户名',
count(o.order_id) '订单数', -- 无订单为0
ifnull(sum(o.order_amount), 0) '总消费' -- 无订单时总消费为0,避免NULL
from user u
left join `order` o on u.id = o.user_id -- 关联条件:用户ID=订单用户ID
group by u.id -- 按用户分组,必须包含非聚合字段的主键
order by 订单数 desc;
- 内连接(INNER JOIN):只查询有订单的用户(如筛选付费用户)
select
u.username '用户名',
o.order_id '订单ID',
o.order_amount '订单金额'
from user u
inner join `order` o on u.id = o.user_id
where o.order_amount > 100 -- 筛选金额>100的订单
order by o.order_time desc;
3.2.3 聚合函数(COUNT/SUM/AVG 等)
-- 1. 统计用户总数(count(*)包含NULL,推荐使用)
select count(*) as '总用户数' from user;
-- 2. 统计订单总金额、平均金额、最大金额
select
sum(order_amount) '总销售额',
avg(order_amount) '平均订单金额',
max(order_amount) '最大订单金额'
from `order`;
-- 3. 按条件分组统计(group by + having)
-- 示例:统计订单数>=2的用户
select
u.username '用户名',
count(o.order_id) '订单数'
from user u
left join `order` o on u.id = o.user_id
group by u.id
having 订单数 >= 2; -- having筛选分组后的结果,where筛选分组前的行
3.3 索引优化(提升查询速度的核心)
3.3.1 索引的作用与类型
索引类型 | 特点 | 适用场景 |
---|---|---|
主键索引 | 默认自动创建(primary key ),唯一非空 |
主键查询(如where id=1 ) |
唯一索引 | unique 约束自动创建,确保字段唯一 |
唯一字段查询(如username 、email ) |
普通索引 | 手动创建,无约束,仅加速查询 | 高频非唯一字段查询(如age 、create_time ) |
复合索引 | 基于多个字段创建(如username+create_time ) |
多条件联合查询(如where username='zhangsan' and create_time>'2024-01-01' ) |
全文索引 | 针对文本字段的模糊查询优化 | 替代like '%关键词%' (如邮箱、文章内容查询) |
3.3.2 索引创建与删除(实战代码)
-- 1. 创建普通索引(针对age字段,高频用于年龄筛选)
create index idx_user_age on user(age);
-- 2. 创建复合索引(针对username+create_time,适配“按用户名查询并按时间排序”场景)
create index idx_user_name_time on user(username, create_time);
-- 3. 创建全文索引(针对email字段,支持模糊查询邮箱关键词)
create fulltext index idx_user_email_ft on user(email);
-- 4. 查看表中所有索引(验证索引是否创建成功)
show index from user;
-- 5. 删除索引(索引过多会影响插入/更新性能,需定期清理无用索引)
drop index idx_user_age on user;
3.3.3 索引失效的 8 种常见场景(避坑指南)
使用函数或运算操作索引字段: select * from user where age + 1 = 26;(失效,应改为age = 25); 字符串不加引号: select * from user where username = 123;(失效,username 是字符串类型,需加引号'123'); 模糊查询以 % 开头: select * from user where username like '%zhang';(失效,改为zhang%可命中索引); 违背最左前缀原则: 复合索引(username, create_time),查询条件where create_time = '2024-01-01'(失效,需包含左前缀 username); 使用 or 连接非索引字段: select * from user where age = 25 or phone = '13800138000';(phone 无索引,导致 age 索引失效); order by 使用非索引字段: select * from user where age = 25 order by email;(email 无索引,导致排序时全表扫描); 数据量过小: 表数据 < 1000 行时,MySQL 会选择全表扫描(索引开销大于查询收益); 索引字段为 NULL: select * from user where email is null;(索引不存储 NULL 值,导致失效,建议字段设为not null default '')。