MySQL万字基础总结

【全文精华无废话,觉得还不错可以加个关注点个赞!!!】

SQL

通用语法与分类
  • DDL数据定义语言,定义数据库对象(数据库、表、字段)。

  • DML数据操作语言,用来对数据库表中数据进行增删改。

  • DQL数据查询语句,用来查询数据库中表的记录。

  • DCL数据控制语言,用来创建数据库用户,控制数据库的访问权限。

DDL

数据库操作

# 查询所有数据库
SHOW DATABASES;
# 查询当前数据库
SELECT DATABASE();
#创建数据库
CREATE DATABASE IF NOT EXISTS  [数据库名] DEFAULT CHARSET utf8mb4;
#删除数据库
DROP DATABASE [IF EXISTS] [数据库名];
#使用某一个数据库
USE 数据库名;

数据库创建可选项:

  • (如果不存在):IF NOT EXISTS

  • (字符集) : DEFAULT CHARSET utf8mb4

  • COLLATE排序规则

数据表操作(创建&查询)

#查询当前数据库所有表(前提是进入到这个数据库)
SHOW TABLES;
#根据表名查看表结构
DESC 表名;
#查询指定表的建表语句
SHOW CREATE TABLE 表名;
#表创建(例)
CREATE TABLE tb_user(
  id INT COMMENT  '编号',
  name VARCHAR(255) COMMENT '姓名',
  age INT COMMENT '年龄',
  gender VARCHAR(1) COMMENT '性别'
) COMMENT '用户表' ;

数据类型相关:

  • DECIMAL:依赖于精度和标度的值,如123.45,精度是5,标度是2。

  • DOUBLE用法 score double(4,1);表示成绩只有4位,其中一位小数。

  • TINYBLOB描述不超过255个字符的二进制数据

  • TINYTEXT描述的是超文本字符串

  • BLOB二进制形式的长文本数据

  • DATE:描述的日期值YYYY-MM-DD

  • TIME:描述的时间值或持续时间HH:MM:SS

  • DATETIME混合时间YYYY-MM-DD HH:MM:SS

  • TIMESRAMP:混合日期和时间值,时间戳

数据表操作(修改&删除)

# 添加字段
ALTER TABLE 表名 ADD 字段名 类型(长度) [COMMENT 注释] [约束];
# 例
ALTER TABLE tb_user ADD nickname varchar(20) COMMENT '昵称';
# 修改数据类型
ALTER TABLE 表名 MODIFY 字段名 新数据类型(长度);
# 修改字段名和字段类型
ALTER TABLE 表名 CHANGE 旧字段名 新字段名 类型(长度) [COMMENT 注释] [约束];
# 删除字段
ALTER TABLE 表名 DROP 字段名;
# 修改表名
ALTER TABLE 表名 RENAME TO 新表名;
# 删除表
DROP TABLE [IF EXISTS] 表名;
# 删除指定表,并重新创建该表
TRUNCATE TABLE 表名;
DML(增删改)

添加数据

# DML- 添加数据
# 给指定字段添加数据
INSERT INTO 表名(字段名1,字段名2...)VALUES (1,2,...);
# 给全部字段添加数据
INSERT INTO 表名 VALUES (1,2,...);
# 批量添加数据
INSERT INTO 表名(字段名1,字段名2...)VALUES (1,2,...),(1,2,...),(1,2,...),;
INSERT INTO 表名 VALUES (1,2,...),(1,2,...),(1,2,...);

更新和删除

# DML-修改数据
UPDATE tb_user SET 字段名1 =1,字段名2 =2,... [where 条件];
# 案例
UPDATE tb_user SET nickname = 'itheima' where id = 1;
# DML-删除数据
DELETE FROM tb_user [WHERE 条件];# 删除符合条件的数据
DQL数据查询语言

DQL语法

# DQL语法结构
SELECT 字段列表
FROM 表名列表
WHERE 条件列表
GROUP BY 分组字段列表
HAVING 分组后条件列表
ORDER BY 排序字段列表
LIMIT 分页参数
# ------------------------------------------------------------------------------------------
# 基本查询-查询返回所有字段
SELECT * FROM tb_user;
# 基本查询-查询返回多个字段
SELECT 字段1,字段2,... FROM tb_user;
# 设置别名
SELECT 字段1 AS 别名,字段2 AS 别名,... FROM 表名;
# 去除重复记录
SELECT DISTINCT 字段列表 FROM 表名;

# DQL条件查询 条件 >, >=, <, <=, <>, BETWEEN...AND..., IN(...), LIKE 占位符(_匹配单个字符,%匹配任意个字符),...

# 聚合函数作用于表中某列数据(所有null不参与计算)
COUNT 统计数量
MAX   最大值
MIN   最小值
AVG   平均值
SUM   求和
[语法] SELECT 聚合函数(字段列表) FROM 表名;

# 分组查询-语法
SELECT 字段列表 FROM 表名 [WHERE 条件] GROUP BY 分组字段名 [HAVING 分组后过滤条件];
#例-根据性别分组,统计男员工和女员工的数量
SELECT gender, COUNT(*) from emp group by gender;
#例-查询年龄小于45的员工,并根据工作地址分组,获取员工数量大于等于3的工作地址。
SELECT workaddress, COUNT(*) FROM emp WHERE age < 45 GROUP BY workadress HAVING COUNT(*) >= 3;

# 排序查询
SELECT 字段列表 FROM 表名 ORDER BY 字段1 排序方式1, 字段2 排序方式2;
# 分页查询LIMIT
SELECT 字段列表 FROM 表名 LIMIT 起始索引,查询记录数;
# 例
SELECT * FROM emp LIMIT 10;

where和having的区别

  • 执行时机不同:where是分组之前进行过滤,不满足where条件则不参与分组;而having是分组之后对结果进行过滤。
  • 判断条件不同:where不能对聚合函数进行判断,而having可以。

分页查询相关

  • 起始索引从0开始,起始索引=(查询页码-1)*每页显示记录数。
  • 若是查询第一页,起始索引可以省略,直接简写为limit 10。
DCL

管理数据库 用户,控制数据库的访问 权限

创建用户itcast,可以在任意主机访问数据库,修改主机名为%即可。

# 查询用户
USE mysql;
SELECT * FROM user;
# 创建用户
CREATE USER '用户名'@'主机名' IDENTIFIED BY '密码';
# 修改用户密码
ALTER USER '用户名'@'主机名' IDENTIFIED WITH mysql_native_password BY '新密码';
# 删除用户
DROP USER '用户名'@'主机名';
###--例
# 创建用户itcast,只能在当前主机localhost访问,密码123456
CREATE USER 'itcast'@'localhost' identified by '123456';
# 创建用户itcast,可以在任意主机访问数据库,密码123456
CREATE USER 'itcast'@'%' identified by '123456';

权限控制

ALL、ALL PRIVILEGES所有权限;SELECT查询数据权限;INSERT/UPDATE/DELETE插入数据/修改数据/删除数据权限;ALTER修改表权限;DROP删除数据库/表/视图权限;CREATE创建数据库/表权限;

# 查询权限
SHOW GRANTS FOR '用户名'@'主机名';
# 授予权限:给哪个用户授予那张数据库表的什么权限。
GRANT 权限列表 ON 数据库名.表名 TO '用户名'@'主机名';
# 给某用户授予所有数据库的所有表权限就是*
GRANT ALL ON *.* TO 'itheima'@'%';
# 撤销权限
REVOKE 权限列表 ON 数据库.表名 FROM '用户名'@'主机名';

内置函数

字符串函数
# concat 字符串拼接
SELECT CONCAT('hello', ' MySQL');
# lower全部转为小写
SELECT LOWER('Hello');
# upper全部转为大写
SELECT UPPER('hello');
# lpad左填充,第一个参数是要填充的字符串,第二个是长度,第三个是用什么填充
SELECT LPAD('01', 5, '-');
# rpad
SELECT RPAD('01', 5, '-');
# TRIM 去掉字符串头部和尾部的空格
SELECT TRIM(' HELLO MYSQL ');
# substring,第二个参数是索引起始位置,第三个是截取几个
SELECT SUBSTRING('HELLO MYSQL',1,5);

mysql中索引从1开始

数值函数

SELECT CEIL(1.1);#向上取整
SELECT FLOOR(1.1);#向下取整
SELECT MOD(3,4);#取模余
SELECT RAND();#求随机数0-1之间
SELECT ROUND(2.345,2);#对第一个参数四舍五入保留2个参数(第二个参数指定保留的小数位数)
#例
# 生成六位随机验证码
SELECT LPAD(ROUND(RAND()*1000000,0),6,'0');
日期函数
SELECT CURDATE();#返回当前日期
SELECT CURTIME();#返回当前时间
SELECT NOW();# 返回当前日期和时间
SELECT YEAR(NOW());#返回当前时间对应的年份
SELECT MONTH(NOW());
SELECT DAY(NOW());
SELECT DATE_ADD(now(),INTERVAL 10 DAY);#当前时间后推10天的日期
SELECT DATEDIFF('2021-12-01','2021-11-01');#两个日期相差的天数
流程控制函数

IF(value,value1,value2) 如果value的值为TRUE,返回value1,否则返回value2
IFNULL(value1, value2) 如果value1不为NULL,返回value1,否则返回value2
CASE WHEN 条件1 THEN 结果1 WHEN 条件2 THEN 结果2 … [ELSE resultn] END 相当于Java的if…else if…else…
CASE expr WHEN 常量值1 THEN 值1 WHEN 常量值1 THEN 值1 … [ELSE 值n] END 相当于Java的switch…case…

SELECT IF(1 > 0,'正确','错误'); 
->正确
SELECT IFNULL(null,'Hello Word');
->Hello Word    
SELECT CASE 
  WHEN 1 > 0
  THEN '1 > 0'
  WHEN 2 > 0
  THEN '2 > 0'
  ELSE '3 > 0'
  END;
->1 > 0
SELECT (CASE workaddress 
  WHEN '北京' THEN '一线城市'
  WHEN '上海' THEN '一线城市'
ELSE '二线城市' END) as '工作地址'
FROM emp;
#---------------------------------
SELECT employee_id,salary, CASE WHEN salary>=15000 THEN '高薪' 
				  WHEN salary>=10000 THEN '潜力股'  
				  WHEN salary>=8000 THEN '屌丝' 
				  ELSE '草根' END  "描述"
FROM employees; 
#---------------------------------
SELECT oid,`status`, CASE `status` WHEN 1 THEN '未付款' 
								   WHEN 2 THEN '已付款' 
								   WHEN 3 THEN '已发货'  
								   WHEN 4 THEN '确认收货'  
								   ELSE '无效订单' END 
FROM t_order;
#---------------------------------
SELECT CASE WHEN 1 > 0 THEN 'yes' WHEN 1 <= 0 THEN 'no' ELSE 'unknown' END;
#---------------------------------
SELECT last_name, job_id, salary,
       CASE job_id WHEN 'IT_PROG'  THEN  1.10*salary
                   WHEN 'ST_CLERK' THEN  1.15*salary
                   WHEN 'SA_REP'   THEN  1.20*salary
       			   ELSE      salary END     "REVISED_SALARY"
FROM   employees;
#---------------------------------
SELECT employee_id,12 * salary * (1 + IFNULL(commission_pct,0))
FROM employees;

约束

约束是作用于表中字段上的规则,用于限制存储在表中的数据。

目的:保证数据库中数据的正确、有效和完整。

分类:非空约束、唯一约束、主键约束、默认约束、检查约束、外键约束等。

# ---------------约束---------------------
create table user(
    id int primary key auto_increment comment '主键',
    name varchar(10) not null unique comment '姓名',
    age int check ( age > 0 && age <=120 ),
    status char(1) default '1' comment '状态',
    gender char(1) comment '性别'
)comment '用户表';
#插入验证
insert into user(name, age, status, gender) values ('Tom1',19,'1','男'),('Tom2',25,'0','男');

# ---添加外键
create table 表名(
    字段名 数据类型,
    ...,
    constraint [外键名称] foreign key (外键字段名) reference 主表(主表列名)
);
# 添加外键
alter table 表名 add constraint 外键名称 foreign key (外键字段名) references 关联的主表(主表列名);
# ---删除外键
alter table 表名 drop foreign key 外键名称;
# 删除/更新行为
# 例
alter table emp add constraint fk_emp_dept_id foreign key (dept_id) references dept(id) on update cascade on delete cascade;

多表查询

多表关系:一对一、一对多(多对一)、多对多

# 多对多
use test;
create table student(
    id int auto_increment primary key comment '主键ID',
    name varchar(10) comment '姓名',
    no varchar(10) comment '学号'
)comment '学生表';
insert into student values (null,'戴琦丝','2000100101'),
                           (null,'谢逊','2000100102'),
                           (null,'殷天正','2000100103'),
                           (null,'韦一笑','2000100104');
create table course(
    id int auto_increment primary key comment '主键ID',
    name varchar(10) comment '课程名字'
)comment '课程表';
insert into course values (null, 'java'),(null, 'MySQL'),(null, 'Hadoop');
create table student_course(
    id int auto_increment comment '主键' primary key ,
    studentid int not null comment '学生ID',
    courseid int not null comment '课程ID',
    constraint fk_courseid foreign key (courseid) references course (id),
    constraint fk_studentid foreign key (studentid) references student (id)
)comment '学生课程中间表';
insert into student_course values (null,1,1),
                                  (null,1,2),
                                  (null,1,3),
                                  (null,2,2),
                                  (null,2,3),
                                  (null,3,3);
多表查询-概述

**笛卡尔积:**笛卡尔乘积是指在数学中,两个集合 A集合和B集合 的所有组合情况。(在多表查询时,需要消除笛卡尔积)

消除笛卡尔积:令A集合外键等于B集合主键。

连接查询

  • 内连接:相当于查询A、B交集部分数据
  • 外连接:
    • 左外连接,查询左表所有数据,以及两张表交集部分数据。
    • 右外连接,查询右表所有数据,以及两张表交集部分数据。
  • 自连接:当前表与自身的连接查询,自连接必须使用表别名。

子查询

连接查询—内连接
# 隐式内连接
SELECT 字段列表 FROM1,2 WHERE 条件...;
## -例 查询每一个员工的姓名,及关联的部门的名称(为表起了别名就不能用原名来限制字段了)
select emp.name,dept.name from emp, dept where emp.dept_id = dept.id;
select e.name,d.name from emp e, dept d where e.dept_id = d.id;
# 显式内连接
SELECT 字段列表 FROM1 [INNER] JOIN2 ON 连接条件...;
## -例 查询每一个员工的姓名,及关联的部门的名称
select e.name, d.name from emp e inner join dept d on e.dept_id = d.id;
连接查询—外连接
# 左外连接
SELECT 字段列表 FROM1 LEFT [OUTER] JOIN2 ON 条件...;
## -例 查询emp表所有数据和对应的部门信息。emp表中有个员工对应的部门是null
select e.*, d.name from emp e left outer join dept d on e.dept_id = d.id;
# 右外连接
SELECT 字段列表 FROM1 RIGHT [OUTER] JOIN2 ON 条件...;
连接查询—自连接

自连接查询,可以是内连接查询,也可以是外连接查询。

SELECT 字段列表 FROM 表A 别名 JOIN 表A 别名B ON 条件...;
# 例--查询员工及其所属领导的名字(涉及到一张表)(但是单表查询做不出来,要看成两张表去做)
select a.name, b.name from emp a, emp b where a.managerid = b.id;

LeetCode181子查询和自连接

题目和链接:超过经理收入的员工

select a.name as Employee
from Employee a, Employee b 
where a.managerId = b.id
and a.salary > b.salary;
联合查询-union,union all

对于union查询,就是把多次查询接合起来,形成一个新的查询结果集。

SELECT 	字段列表 FROM 表A ...
UNION [ALL]
SELECT 字段列表 FROM 表B...;
## -将薪资低于5000的员工,和年龄大于50岁的员工全部查询出来。
select * from emp where salary < 5000
union all
select * from emp where age > 50;
# union all直接将查询结果合并
# union 会对查询结果去重再合并
# 联合查询要求多张表的列数及字段类型要保持一致
子查询(嵌套查询)
# 子查询
select * from t1 where column1 = (select column1 from 2);
## 分为标量子查询(查询结果为单个值),列子查询(查询结果为一列)、行子查询、表子查询(查询结果为多行多列)
## where之后出现,from之后出现、select之后出现

# 标量子查询
# --例-查询销售部所有员工信息
select * from emp where dept_id = (select id from dept where name = '销售部');

# 列子查询
##常用操作符:IN、NOT IN、ANY、SOME、ALL
### ANY在子查询的列表中只要有一个满足就可以。
### SOME与ANY等同
# --例 查询销售部和市场部的所有员工信息
## a.查询销售部和市场部的部门id
## b.根据部门id查询员工信息
select * from emp 
where dept_id in 
(select id from dept where name = '销售部' or name = '市场部');

# 行子查询
## 常用操作符 =、<>、IN、NOT IN
# 例-查询与“张无忌”的薪资及直属领导相同的员工信息
## a.查询张无忌的薪资与直属领导
## b.查询与“张无忌”的薪资及直属领导相同的员工信息
select * from emp where (salary,managerid) = (select salary,manager from emp where name = '张无忌');
## 注意:salary = 12500 and managerid = 1等价于 (salary,managerid) = (12500,1)

# 表查询
## 常用操作符 IN
# 例-查询与“鹿杖客”,“宋远桥”的职位和薪资相同的员工信息。
## a.查询“鹿杖客”,“宋远桥”的职位和薪资信息
## b.查询与“鹿杖客”,“宋远桥”的职位和薪资相同的员工信息。
select * from emp
where (jod,salary) in
(select job,salary from emp where name = "鹿杖客" or name = "宋远桥");

事务

是一组操作的集合,是一个不可分割的单位,要么同时成功,要么同时失败。

事务操作

# 查看/设置事务提交方式
SELECT @@autocommit;
SET @@autocommit = 0; #	手动提交
# 提交事务
COMMIT;
# 回滚事务
ROLLBACK;
# 开启事务(所有事务如果执行成功,就提交事务,否则回滚事务)
START TRANSACTION;
四大特性

原子性

一致性

隔离性

永久性

并发事务问题

脏读:一个事务读到另一个事务还没有提交到数据。

不可重复读:一个事务先后读取同一条记录,但两次读取到数据不同。

幻读:一个事务按条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,好像出现了‘幻影’。

事务隔离级别

读未提交、读已提交、可重复读(mysql默认)、串行化

# 查看事务隔离级别
SELECT @@TRANSACTION_ISOLATION
# 设置事务隔离级别
SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}

存储引擎

体系结构图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5VcXa74E-1663421953977)(assets/image-20220913145200469.png)]

存储引擎

存储引擎就是存储数据、建立索引、更新/查询数据等技术的实现方式。存储引擎是基于表的,而不是基于库的,所以存储类型也可被称为表类型。

# 查询当前数据库支持的存储引擎
show engines;
# 创建表并指定引擎 [例]
create table my_myisam(
	id int
) engine = MyISAM;

InnoDB引擎

是一种兼顾高可靠性和高性能的通用存储引擎。

特点:DML操作遵循ACID(事务的四大特性)模型,支持事务行级锁,提高并发访问性能;支持外键FOREIGN KEY约束,保证数据的完整性和正确性。

InnoDB逻辑存储结构

表空间、段、区、页、行

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TfZ0Vjp1-1663421953978)(assets/image-20220913151215553.png)]

表空间中包含多段,段中包含多区,区中包含多页,也中包含多行。行指的就是我们在表中的一行一行。

每row行中就是事务的Id、指针、一个一个的字段。一个页16k,一个区1M最多包含64个页。

MyISAM

MyISAM是MySQL早期的默认存储引擎。特点:不支持事务,不支持外键;支持表锁,不支持行锁;访问速度快。

Memory

Memory引擎的表数据存在内存中,受硬件问题或断电问题影响,只能作为临时表或缓存使用。

特点:内存存放、hash索引(默认)

索引

索引:帮助MySQL高效获取数据的数据结构(有序)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-umMKuWfe-1663421953978)(assets/image-20220913160558752.png)]

优点:提高数据检索的效率,降低数据库的IO成本。

​ 通过索引对数据进行排序,降低数据排序的成本,降低CPU的消耗。

缺点:索引列也要占空间。

​ 大大提高了查询效率,但降低了更新表的速度。

索引结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gjV86EYN-1663421953978)(assets/image-20220913162433438.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kuZ08OK4-1663421953978)(assets/image-20220913162452318.png)]

Btree

B+树相对于B树区别:

  • 所有数据都会出现在叶子节点
  • 叶子节点形成一个单向链表

B+树,数据的存储在叶子节点,索引节点不存储数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4y5bPFio-1663421953979)(assets/image-20220913164935745.png)]

hash索引

哈希索引就是采用一定的hash算法,将键值换算成新的hash值,映射到对应的槽位上,然后存储在hash表中。

链表可以解决hash冲突。不支持范围查询。

支持hash索引的是Memory引擎,InnoDB具有自适应hash功能。

InnoDB存储引擎使用B+tree索引结构原因:

  • 相对于二叉树,层级更少,搜索销量高;
  • 对于B-tree,无论叶子节点还是非叶子节点,都会保存数据,这样导致一页中存储的键值更少,指针跟着减少,要同样保存大量数据,只能增加树的高度,导致性能降低;
  • 相对于hash索引,B+tree支持范围匹配及排序操作;

索引分类

主键索引(只能有一个)、唯一索引(可以避免同一个变种某数据列中的值重复)、常规索引、全文索引FULLTEXT

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-owvTRDOK-1663421953979)(assets/image-20220913191342449.png)]

聚集索引、二级索引

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fPgYSiNO-1663421953979)(assets/image-20220913191320548.png)]

聚集索引选取规则:

  • 如果存在主键,主键索引就是聚集索引
  • 如果不存在主键,将使用第一个唯一索引作为聚集索引。
  • 如果没有主键,或没有合适的唯一索引,则InnoDB会自动生成一个rowid作为隐藏的聚集索引。

回表查询:先根据二级索引去找,找到对应的id值,再根据聚集索引值拿到对应的行数据。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oEfT0Ux4-1663421953979)(assets/image-20220913192750365.png)]

索引语法
# 创建索引
CREATE [UNIQUE|FULLTEXT] INDEX index_name ON table_name (index_col_name,字段名...);
# 查看索引
SHOW INDEX FROM table_name;
# 删除索引
DROP INDEX index_name ON table_name;
SQL性能分析

根据SQL执行频率,判断此类数据库以什么为主(增删改查)。

# 查当前数据库的INSERT、UPDATE等访问频次
SHOW GLOBAL STATUS LIKE 'Com_____';
# 查服务器状态
SHOW [SESSION | GLOBAL] STATUS;

慢查询日志,记录了所有执行时间超过指定参数(long_query_time,单位秒,默认10秒)等所有SQL语句的日志。

MySQL慢查询日志默认没有开启,需要在MySQL的配置文件(/etc/my.cnf)中配置如下信息:

# 查询慢查询日志是否开启
show variables like 'slow_query_log';
## 开启(在my.cnf)
### 开启慢日志查询开关
slow_query_log = 1
### 设置慢日志时间,超过该时间就是慢查询,记录慢查询日志
long_query_time = 2

profile详情:有些操作执行时间可能达到慢查询时间的左边缘,比如1.95秒,这类SQL也是相对性能较低的,我们也要对这部分SQL进行优化,如何定位到该处sql,慢查询日志满足不了。这时候就要用到profile详情。

show profiles 能够帮助我们了解时间都耗费到哪里去了,通过have_profiling参数,能看到当前数据库是否支持profile操作:select @@have_profiling;

# 查询是否支持profile操作
select @@have_profiling;
# 查询是否开启profiling
select @@profiling;
# 开启session/global级别的profiling
SET [SESSION|GLOBAL] profiling = 1;
# 查看sql耗时情况
SHOW profiles;
# 查看指定query_id的SQL语句各个阶段的耗时情况
SHOW profile FOR QUERY query_id;
# 查看置顶query_id的SQL语句CPU的使用情况
SHOW profile cpu FOR QUERY query_id;

explain执行计划,explain或者DESC命令获取mysql如何执行select语句的信息,包括在select语句执行过程中表如何连接和连接的顺序。

## 语法-直接在select语句之前加上关键字explain/desc
EXPLAIN SELECT 字段列表 FROM 表名 WHERE 条件;

explain查询到的执行计划每列的含义:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7TtOdkkk-1663421953979)(assets/image-20220914170853458.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IZZMQhoV-1663421953979)(assets/image-20220914171109921.png)]

索引使用
  • 验证索引效率,在未建立索引之前,执行如下sql语句,查看sql的耗时。
# 根据id去查非常快
select * from tb_sku where id = 1;
# 根据sn查(sn这个字段没有索引,数据量多耗时很大)
select * from tb_sku where sn = '100000000003145001';
# 为sn字段创建索引(B+tree结构)
create index idx_sku_sn on tb_sku(sn);
# 再次执行select * from tb_sku where sn = '100000000003145001';耗时非常短
# 在select语句前加上explain可查看该语句执行计划

索引使用法则–最左前缀法则

该法则主要针对于联合索引。如果索引了多列(联合索引),要遵循最左前缀法则。最左前缀法则指的是查询从索引的最左列开始,并且不跳过索引中的列。如果跳过了某一列,索引将部分失效(后面的字段索引失效)。

# profession、age、status是关联的索引,顺序依次是1、2、3
select * from tb_user where profession = '软件工程' and age = 31 and status = '0';
# 如果查的时候将age这个条件删除,将出现部分失效,最后面的status字段将失效。
# 如果查询的时候删除profession条件,将不再走索引查询,不满足最左前缀法则

索引使用法则–索引失效情况

  • 索引列运算,不要在索引列上进行运算操作,否则索引将失效。

  • 字符串类型字段使用时不加引号,索引将失效。

  • 如果头部模糊匹配,索引将失效。(仅仅尾部模糊匹配,索引不会失效)

  • 用or分割开的条件,如果or前的条件的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到。(只有两侧都有索引,索引才不会失效)

  • 数据分布影响,如果mysql评估使用索引比全表更慢,则不适用索引。

SQL提示

简单来说,就是在SQL语句中加入一些人为的提示来达到优化操作的目的。

use index: # 告诉数据库用哪个索引
explain select * from tb_user use index(idx_user_pro) where profession = '软件工程';
ignore index: # 告诉数据库不要用哪个索引
explain select * from tb_user ignore index(idx_user_pro) where profession = '软件工程';
force index: # 告诉数据库必须走这个索引
explain select * from tb_user force index(idx_user_pro) where profession = '软件工程';

覆盖索引

尽量使用覆盖索引(其实就是select后面怎么写),减少使用select *;

注(执行explain后extra中出现):using index condition:查找使用了索引,但是需要回表查询数据

​ using where; using index:查找使用了索引,但是需要的数据在索引列中都能找到,所以不需要回表查询数据。

如下就是覆盖索引,需要查的在索引列中都能找到,不需要回表。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HEU2nK2R-1663421953979)(assets/image-20220915153513999.png)]

前缀索引

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SvSAhtiZ-1663421953979)(assets/image-20220915154508727.png)]

# 语法 # 此处n表示要提取字符串的前几个字符来构建索引
create index idx_xxx on table_name(column(n)); 

前缀长度的确定;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RTE0ACwI-1663421953980)(assets/image-20220915154740642.png)]

## 计算公式
select count(distinct email)/ count(*) from tb_user;
select count(distinct substring(email,1,5))/ count(*) from tb_user;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nx5wpDe0-1663421953980)(assets/image-20220915155410955.png)]

单列索引&联合索引

一个索引包含单个列;一个索引包含多个列;

先按phone来排序,若phone相同,再按name排序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0n3mut5B-1663421953980)(assets/image-20220915155652080.png)]

索引设计原则

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CzjYJr7u-1663421953980)(assets/image-20220915155836689.png)]
更多内容详在:https://liyi243.cn/web/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

快乐大队队长

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值