0.缩写
db  //数据库
tbl //表
fld //字段
typ //类型
_   //用下划线拼接区分不同如 name a/b/c x/y/z 1/2/3
    //我们尽量保证前缀相同
1.基本的sql

①.库操作

show databases;
create database db_name;
use db_name;
drop database db_name;

②.表操作

show tables;
desc tbl_name;
drop table tbl_name;
alter table tbl_name add/modify/change/drop/rename to ...;
show create table tbl_name;      //显示创建这样的表需要的创建语句
create table tbl_name (          //可以用show create table tbl_name;然后对着写
    id int unsigned not null auto_increment comment '用户id',
    username varchar(50) not null unique comment '用户名',
    email varchar(100) not null comment '邮箱',
    password varchar(255) not null comment '加密密码',
    primary key (id)
) engine=innodb default charset=utf8mb4;

③.表数据操作

insert into tbl_name (fld1, fld2, fld3)
values
(fld1_val1, fld2_val1, fld3_val1),
(fld1_val2, fld2_val2, fld3_val2),
...;

update table set fld1=val1, fld2=val2 where 条件;
delete from tbl_name where 条件;
select from where group by having order by limit;

④.用户管理 用户名+ip 构造用户的唯一索引

create user `用户名`@`ip` identified by `密码`;
alter user `用户名`@`ip` identified with mysql_native_password by `密码`;
drop user `用户名`@`ip`;
grant 权限列表 on db_name.tbl_name to `用户名`@`ip`;
revoke 权限列表 on db_name.tbl_name from `用户名`@`ip`;
flush privileges;
2.关键字的执行顺序
步骤 实际执行顺序 说明
from 确定数据源(表/子查询/视图) 建立连接(JOIN)
on 处理JOIN条件 (只对连接语句有效)
join 执行连接,生成临时结果集
where 对结果集做行级过滤(非分组过滤)
group by 分组操作 (如果有分组 select 只能查询分组字段或者聚合数据)
having 对分组结果做组级过滤 (只能过滤聚合后的结果)
select 选择字段/表达式/函数/聚合  可以对字段起别名关键字 as 可以省略
distinct 去重
order by 排序
limit 取指定的前N条记录
3.约束

①.所有约束

约束类型 说明
数据类型约束 插入的值必须符合字段的数据类型
NOT NULL 不能插入 NULL
DEFAULT 如果未指定字段值,将使用默认值
主键约束(PRIMARY KEY) 字段值必须唯一且非NULL
唯一约束(UNIQUE) 字段值必须唯一
自增约束(AUTO_INCREMENT) 如果字段自增,不应手动插入重复值
CHECK约束 字段值必须满足自定义表达式条件(MySQL 8.0+支持)
外键约束(FOREIGN KEY) 字段值必须在父表中存在 (比如员工归属部门)
SQL模式影响(sql_mode) 控制错误行为是报错还是自动修正(如类型转换、截断过长字符)

②.外键约束的行为

行为 说明 示例结果
NO ACTION 如果有子表记录引用,拒绝对父表的删除或关联字段更新 部门x里面有员工,则部门x不能被删除或部门id更新
RESTRICT 同上 同上
CASCADE 父表记录被删除/更新时,子表对应记录也自动被删除/更新 删除部门,则该部门员工也被删除
SET NULL 父表记录被删除/更新时,子表中对应字段设为NULL(需允许为 NULL) 删除部门,则员工的部门id变为NULL
SET DEFAULT 父表记录被删除/更新时,子表字段设为默认值(⚠️innodb不支持此选项) ❌不可用(语法接受但无效)
4.多表

①.多表的关系

关系 说明 示例结果
一对多 子表关联父表的主键 比如说员工和部门
多对多 需要建立中间表,中间表包含两个外键,关联两张表的主键 学生/选修课 中间表:学生id,选修课id
一对一 用于表结构拆分,在任意一张表设置外键,关联另外一张表的主键 垂直分表

②.标量子查询

select * from 员工表 where 部门id = (select id from 部门表 where name = '销售部');

③.列子查询

select * from 员工表 where 部门id in (select id from 部门表 where name = '销售部' or name = '市场部');
select * from 员工表 where fld_工资 > all (select fld_工资 from 员工表 where 部门id = (select id from 部门表 where name = '财务部'))
select * from 员工表 where fld_工资 > any (select fld_工资 from 员工表 where 部门id = (select id from 部门表 where name = '财务部'))

③.行子查询

select * from 员工表 where (fld_工资,fld_leader) = (select fld_工资, fld_leader from 员工表 where name='张三丰');

④.表子查询

select e.*, d.* from (select * from 员工表 where fld_入职时间 > '2025-06-18') e left join 部门表 d on e.部门id=d.id

⑤.子查询可以在select/where/from之后

select
  e.name,       -- 查询员工名字
  (select d.fld_部门名 from 部门表 d where e.部门id=d.id) as department_name --查部门名
from
  员工表 e;  -- 员工表为主表
5.笛卡尔积

①.表tbl_a有字段fld_a,表tbl_b有字段fld_b,把fld_a的第一行和fld_b的每一行组合
②.如果是on fld1=fld2jion条件那么把 fld_a的第一行和fld_b的每一行组合只有等于fld_a第一行的会保留下来
③.左连接是以左边的表为基准查找,右连接是以右边的表为基准查找
  比如tbl_a left join tbl_a, 即使fld_b的所有行都不等于fld_a的第一行,但是因为fld_a是基准表所以第一行会被保留

6.explain

①.id: 查询编号
   体现在多表查询join或者有子查询的时候
   id越大(子查询)会优先执行,结构会传给id小的(父查询),id相同的由优化器决定哪个先执行
②.select_type: 更多的是描述当前id在多表查询中的位置 所以意义并不是很大

select_type 含义
SIMPLE 简单查询,不包含子查询或 UNION
PRIMARY 最外层的主查询
SUBQUERY 子查询(出现在 SELECT, WHERE, HAVING 等中)
DERIVED 派生表(子查询在 FROM 子句中,MySQL会生成临时表)
DEPENDENT SUBQUERY 子查询依赖外部查询结果,必须嵌套执行(相关子查询)
DEPENDENT DERIVED 派生表依赖外部结果,较少见(嵌套派生表)
UNION UNION中的第二个及后续查询
UNION RESULT 保存UNION的最终结果(内部用临时表)
MATERIALIZED MySQL8.0+引入:子查询缓存落地,即子查询提前执行并缓存为临时表
CTE 公共表达式(WITH子句中的临时表,MySQL8.0+)

④.partitions: 如果用了分区表,这里显示命中的分区;否则为 NULL

⑤.type: 表的访问类型,效率从高到低排序

type 含义说明
system 表只有一行(系统表级别)
const 常量引用(主键或唯一索引等于某常量)
eq_ref 联表查询时驱动表关联被驱动表的字段是主键 (见下面案例) (主键join)
ref 非唯一索引查找 (如普通索引/前缀索引/普通键join)
fulltext 使用全文索引(MySQL特有关键字)
ref_or_null 查找索引+额外判断是否为NULL
index_merge 多个索引联合使用(使用and或者or查找多个索引 mysql最后会取交集或者并集)
range 范围查询,如 BETWEEN > < IN(…)
index 扫描整个索引树(比如索引覆盖)
ALL 全表扫描(最差,需要优化)

 eq_ref 案例
 为什么说eq_ref比ref快都是在join的时候,如果驱动表关联被驱动表的字段不是主键/唯一键 而是普通索引 那就是ref
 在没有join的时候 eq_ref就是const

SELECT *                           //整体的时间复杂度 O(m*log(n))
FROM orders o                      //orders:驱动表 外层循环,每次提供一行数据  时间复杂度1次遍历 O(m)
JOIN users u ON o.user_id = u.id;  //user:被驱动表 内层循环,针对驱动表的每一行做匹配 时间复杂度 O(log(n))

⑥.possible_key: 优化器判断”可能”会用到的索引
⑦.key: 实际使用的索引
⑧.key_len: 使用的索引长度(估计) (单位:字节)
     精度是以字段为单位:只会出现使用这个字段或者没有使用这个字段不会说用了0.5个该字段
     实际使用的联合索引字段要用EXPLAIN FORMAT=JSON 查看used_key_parts字段
     例如有abc字段的联合索引,如果查找条件是a=1&b>=1&c=1那么就只会用到ab两个字段
     联合索引在遇到第一个范围查询(>, <, >=, BETWEEN, LIKE 非前缀) 后就“停止向后匹配”了
⑨.rows: mysql预估的扫描行数
⑩.filtered: 预估扫描行里面有%多少个点会通过WHERE过滤条件 越大越好
⑩.Extra: 附加信息,例如是否使用索引、是否临时表、文件排序等

7.索引

①.

②.

③.

④.

⑤.

⑥.

⑦.告诉mysql用哪个索引

//use index:    建议mysql使用哪个索引
//ignore index: 告诉mysql忽略哪个索引
//force index:  强制mysql使用哪个索引
select * from tbl_user user index(idx_user_pro) where profession='计算机'

⑧.索引设计原则

1.针对数据量大,且查询频繁的表建立索引
2.针对查询条件where/order by/group by的操作字段建索引
3.选择选择性高的字段作为索引,尽量使用唯一索引(选择性=1)
4.如果是字符型字段,字符比较长,可以选择前缀索引
5.尽量使用联合索引,索引覆盖可以避免回表
6.索引数量越多,增删改的效率就会降低
7.如果字段不为null时,需要用not null来约束,否则该字段作为索引时会多出一个bit来标识是否为null
8.优化

①.insert优化
  如果插入的数据过多可以选择load(注:load也要按主键顺序插入),语法如下

mysql --local-infile -u -p
set global local_infile=1;
load data local infile '/data/sql.log' into `tbl_name` fields terminated by ',' lines terminated by '\n';

②.order by优化
  尽量使用索引覆盖,并且order by的顺序和联合索引顺序一致

type:ALL             //扫描全表
type:index:          //索引覆盖
Extra:Using filesort //在缓冲区完成排序 如果不可避免使用这个方式 可以调节排序缓冲区的大小sort_buffer_size(默认256k)
                     //如果缓冲区不够大,会涉及磁盘排序,效率会更低
Extra:Using index    //通过索引直接返回有序的数据
select是否索引覆盖 是否按索引顺序排序 type Extra
ALL Using filesort
ALL Using filesort
index Using index; Using filesort
index Using index

③.group by优化
  尽量按索引顺序group by,如果没有索引或者没有按索引顺序group会使用临时表 (Extra: Using temporary)
④.limit优化
  limit 2000000, 10 mysql需要排序前面的2000000条数据最后返回2000000-2000010的记录
  可以记录前200w的最大主键id,查询: WHERE id > id_max_200w ORDER BY id LIMIT 10;
  如果查找条件是联合索引,那就得是索引覆盖
⑤.count优化
  MyISAM引擎把有多少行这个统计数据记录在磁盘了,执行count(*)的时间复杂度是O(1)
  InnoDB的几种count方法效率从低到高

写法 InnoDB处理方式 性能评估
count(非主键) 遍历聚簇索引,返回整行数据给服务层判断该字段是否非NULL计数+1 最慢
count(非主键 not null) 如果该字段和查找条件能被索引覆盖,则仅遍历索引,否则同上每行计数 较慢(取决于是否覆盖索引)
count(主键) 遍历聚簇索引的主键列,返回主键给服务层计数+1 中等
count(1) 遍历聚簇索引,不取任何字段,仅服务层为每行加1
count(*) 遍历聚簇索引,不取字段,不处理NULL,直接统计物理行数 最快

⑥.update优化
  InnoDB的行锁是基于索引加的锁,不是直接锁住数据行本身。
  如果不使用索引(或索引失效) 导致全表扫描,那么InnoDB无法定位具体行,就会退化为加表锁,以保证一致性。

9.触发器

①.概念
  行级触发器: 修改了多少行就会触发多少次
  语句触发器: 一条sql语句不管修改了多少行数据,只会触发一次 (注:mysql不支持)

  关键字old: 触发器能获取到修改之前的行数据
  关键字new: 触发器能获取到修改之后的行数据

②.语法 (在users表被update时记录操作内容)

create trigger trg_users_update
after update on tbl_users
for each row
begin
  insert into tbl_users_mod_log (
    act, id_old, name_old, age_old, id_new, name_new, age_new
  )
  values (
    'update',
    old.id, old.name, old.age,
    new.id, new.name, new.age
  );
end;
文档更新时间: 2026-04-17 16:42   作者:morninglu