MySQL高级--个人笔记
学习视频:尚硅谷MySQL数据库高级,mysql优化,数据库优化_哔哩哔哩_bilibili
文档是复制尚硅谷的复习资料,个人只是为了方便复习。
目录
Mysql 逻辑架构简介
1. 整体架构图
1.1 连接层
1.2 服务层
1.3.引擎层
1.4.存储层
2. show profile
2.1 开启 profile
2.2 使用 profile
2.3 大致的查询流程
2.4 SQL 的执行顺序
2.5 MyISAM 和 InnoDB
第 4 章 SQL 预热
1. 常见的 Join 查询图
2. Join 示例
2.1 建表语句
2.2 案例
第 5 章 索引优化分析
1. 索引的概念
1.1 是什么
1.2 优缺点
2. Mysql 的索引
2.1 Btree 索引
2.2 B+tree 索引
2.3 聚簇索引和非聚簇索引
2.4 时间复杂度(扩展)
3. Mysql 索引分类
3.1 单值索引
3.2 唯一索引
3.3 主键索引
3.4 复合索引
3.5 基本语法
4. 索引的创建时机
4.1 适合创建索引的情况
4.2 不适合创建索引的情况
5. 性能分析
5.1 MySql Query Optimizer
5.2 MySQL常见瓶颈
第 6 章 Explain 性能分析
1. 概念
2. Explain 准备工作
3. id
4. select_type
4.1 SIMPLE
4.2 PRIMARY
4.3 DERIVED
4.4 SUBQUERY
4.5 DEPENDENT SUBQUERY
4.6 UNCACHEABLE SUBQUREY
4.7 UNION
4.8 UNION RESULT
5. table
6. type
6.1 system
6.2 const
6.3 eq_ref
6.4 ref
6.5 range
6.6 index
6.8 index_merge
6.9 ref_or_null
6.10 index_subquery
6.11 unique_subquery
7. possible_keys
8. key
9. key_len
10. ref
11. rows
12. Extra
12.1 Using filesort
12.2 Using temporary
12.3 Using index
12.4 Using where
12.5 Using join buffer
12.6 impossible where
12.7 select tables optimized away
第 7 章 批量数据脚本
1. 插入数据
1.1 建表语句
1.2 设置参数
1.3 编写随机函数
1.4 创建存储过程
1.5 调用存储过程
1.6 批量删除某个表上的所有索引
第 8 章 单表使用索引常见的索引失效
1. 全值匹配我最爱
1.1 有以下 SQL 语句
1.2 建立索引
2. 最佳左前缀法则
3. 不要在索引列上做任何计算
3.1 在查询列上使用了函数
3.2 在查询列上做了转换
4. 索引列上不能有范围查询
5. 尽量使用覆盖索引
6. 使用不等于(!= 或者<>)的时候
7. 字段的 is not null 和 is null
8. like 的前后模糊匹配
9. 减少使用 or
10. 练习
11. 口诀
第 9 章 关联查询优化
1. 建表语句
2. 案例
2.1 left join
2.2 inner join
2.3 四个关联查询案例分析
第 10 章 子查询优化
1. 案例
第 11 章 排序分组优化
1. 无过滤不索引
2. 顺序错,必排序
3. 方向反,必排序
4. 索引的选择
5. using filesort
5.1 mysql 的排序算法
5.2 如何优化
6. 使用覆盖索引
7. group by
第 12 章 练习
1. 案例一
2. 案例二
3. 案例三
4. 案例四
5. 案例五
6. 案例六
7. 案例七
MySQL 逻辑架构简介
1. 整体架构图
1.1 连接层
1.2 服务层
Management Serveices & Utilities
|
系统管理和控制工具
|
---|---|
SQL Interface:
|
SQL 接口。接受用户的 SQL 命令,并且返回用户需要查询的结果。比如 select from
就是调用 SQL Interface
|
Parser
|
解析器。 SQL 命令传递到解析器的时候会被解析器验证和解析
|
Optimizer
|
查询优化器。 SQL 语句在查询之前会使用查询优化器对查询进行优化,比如有
where 条件时,优化器来决定先投影还是先过滤。
|
Cache 和 Buffer
|
查询缓存。如果查询缓存有命中的查询结果,查询语句就可以直接去查询缓存中取数据。这个缓存机制是由一系列小缓存组成的。比如表缓存,记录缓存,key 缓存,
权限缓存等
|
1.3.引擎层
1.4.存储层
2. show profile
2.1 开启 profile
2.2 使用 profile
根据 Query_ID,可以进一步执行 show profile cpu,block io for query Query_id 来查看 sql 的具体执行步骤。
2.3 大致的查询流程
2.4 SQL 的执行顺序
![](/assets/blank.gif)
2.5 MyISAM 和 InnoDB
对比项
|
MyISAM | InnoDB |
外键
|
不支持
|
支持
|
事务
|
不支持
|
支持
|
行表锁
|
表锁,即使操作一条记录也会锁住整个表, 不适合高并发的操作
|
行锁, 操作时只锁某一行,不对其它行有影响,
适合高并发 的操作
|
缓存
|
只缓存索引,不缓存真实数据
|
不仅缓存索引还要缓存真实数据,对内存要求较高,而且内存大小对性能有决定性的影响
|
关注点
|
读性能
|
并发写、事务、资源
|
默认安装
|
Y
|
Y
|
默认使用
|
N
|
Y
|
自 带 系 统 表
使用
|
Y
|
N
|
show engines:查看所有的数据库引擎
第 4 章 SQL 预热
1. 常见的 Join 查询图
2. Join 示例
2.1 建表语句
CREATE TABLE `t_dept` (`id` INT(11) NOT NULL AUTO_INCREMENT,`deptName` VARCHAR(30) DEFAULT NULL,`address` VARCHAR(40) DEFAULT NULL,PRIMARY KEY (`id`)) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE `t_emp` (`id` INT(11) NOT NULL AUTO_INCREMENT,`name` VARCHAR(20) DEFAULT NULL,`age` INT(3) DEFAULT NULL,`deptId` INT(11) DEFAULT NULL,empno int not null,PRIMARY KEY (`id`),KEY `idx_dept_id` (`deptId`)#CONSTRAINT `fk_dept_id` FOREIGN KEY (`deptId`) REFERENCES `t_dept` (`id`)) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
INSERT INTO t_dept(deptName,address) VALUES(' 华山 ',' 华山 ');INSERT INTO t_dept(deptName,address) VALUES(' 丐帮 ',' 洛阳 ');INSERT INTO t_dept(deptName,address) VALUES(' 峨眉 ',' 峨眉山 ');INSERT INTO t_dept(deptName,address) VALUES(' 武当 ',' 武当山 ');INSERT INTO t_dept(deptName,address) VALUES(' 明教 ',' 光明顶 ');INSERT INTO t_dept(deptName,address) VALUES(' 少林 ',' 少林寺 ');INSERT INTO t_emp(NAME,age,deptId,empno) VALUES(' 风清扬 ',90,1,100001);INSERT INTO t_emp(NAME,age,deptId,empno) VALUES(' 岳不群 ',50,1,100002);INSERT INTO t_emp(NAME,age,deptId,empno) VALUES(' 令狐冲 ',24,1,100003);INSERT INTO t_emp(NAME,age,deptId,empno) VALUES(' 洪七公 ',70,2,100004);INSERT INTO t_emp(NAME,age,deptId,empno) VALUES(' 乔峰 ',35,2,100005);INSERT INTO t_emp(NAME,age,deptId,empno) VALUES(' 灭绝师太 ',70,3,100006);INSERT INTO t_emp(NAME,age,deptId,empno) VALUES(' 周芷若 ',20,3,100007);INSERT INTO t_emp(NAME,age,deptId,empno) VALUES(' 张三丰 ',100,4,100008);INSERT INTO t_emp(NAME,age,deptId,empno) VALUES(' 张无忌 ',25,5,100009);INSERT INTO t_emp(NAME,age,deptId,empno) VALUES(' 韦小宝 ',18,null,100010);
2.2 案例
select * from t_emp a inner join t_dept b on a.deptId = b.id
2. 列出所有人员及其部门信息
select * from t_emp a left join t_dept b on a.deptId = b.id
3. 列出所有部门的人员信息
select * from t_emp a right join t_dept b on a.deptId = b.id
4. 列出没有部门的人员信息
select * from t_emp a left join t_dept b on a.deptId = b.id where b.id is null
5. 列出没有人员的部门信息
select * from t_emp a right join t_dept b on a.deptId = b.id where a.id is null
6. 所有人员和部门的对应关系
select * from t_emp a left join t_dept b on a.deptId = b.id
union
select * from t_emp a right join t_dept b on a.deptId = b.id
7. 所有没有入部门的人员和没人入的部门
select * from t_emp a left join t_dept b on a.deptId = b.id where b.id is null
union
select * from t_emp a right join t_dept b on a.deptId = b.id where a.id is null
第 5 章 索引优化分析
1. 索引的概念
1.1 是什么
![](/assets/blank.gif)
1.2 优缺点
- 提高数据检索的效率,降低数据库的IO成本。
- 通过索引列对数据进行排序,降低数据排序的成本,降低了CPU的消耗。
- 虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新所带来的键值变化后的索引信息。
- 实际上索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录,所以索引列也是要占用空间的
2. MySQL 的索引
2.1 Btree 索引
![](/assets/blank.gif)
2.2 B+tree 索引
2.3 聚簇索引和非聚簇索引
2.4 时间复杂度(扩展)
![](/assets/blank.gif)
3. Mysql 索引分类
3.1 单值索引
所表一起创建:CREATE TABLE customer (id INT(10) UNSIGNED AUTO_INCREMENT ,customer_no VARCHAR(200),customer_name VARCHAR(200),PRIMARY KEY(id),KEY (customer_name));
单独建单值索引:CREATE INDEX idx_customer_name ON customer(customer_name);
3.2 唯一索引
概念:索引列的值必须唯一,但允许有空值
随表一起创建:CREATE TABLE customer (id INT(10) UNSIGNED AUTO_INCREMENT ,customer_no VARCHAR(200),customer_name VARCHAR(200),PRIMARY KEY(id),KEY (customer_name),UNIQUE (customer_no));
单独建唯一索引:CREATE UNIQUE INDEX id x_customer_no ON customer(customer_no);
3.3 主键索引
概念:设定为主键后数据库会自动建立索引,innodb为聚簇索引
随表一起建索引CREATE TABLE customer (id INT(10) UNSIGNEDAUTO_INCREMENT ,customer_no VARCHAR(200),customer_nameVARCHAR(200),PRIMARY KEY(id));
单独建主键索引:ALTER TABLE customer add PRIMARY KEY customer(customer_no);
删除 建主键索引:ALTER TABLE customer drop PRIMARY KEY ;
修改 建主键索引:必须先删除掉 (drop) 原索引,再新建 (add) 索引
3.4 复合索引
概念:即一个索引包含多个列
随表一起建索引:CREATE TABLE customer (id INT(10) UNSIGNED AUTO_INCREMENT ,customer_no VARCHAR(200),customer_name VARCHAR(200),PRIMARY KEY(id),KEY (customer_name),UNIQUE (customer_name),KEY (customer_no,customer_name));
单独建索引:CREATE INDEX idx_no_name ON customer(customer_no,customer_name);
3.5 基本语法
操作
|
命令
|
---|---|
创建
|
CREATE [UNIQUE ] INDEX [indexName] ON table_name(column))
|
删除
|
DROP INDEX [indexName] ON mytable;
|
查看
|
SHOW INDEX FROM table_name\G
|
使 用 Alter
命令
|
ALTER TABLE tbl_name ADD PRIMARY KEY (column_list) : 该语句添加一个主键,
这意味着索引值必须是唯一 ,且不能为 NULL 。
|
ALTER TABLE tbl_name ADD PRIMARY KEY (column_list)这条语句创建索引的值
必须要是唯一的 (除NULL外,NULL可能会出现多次)
|
|
ALTER TABLE tbl_name ADD INDEX index_name (column_list): 添加普通索引,
索引值可出现多次。
|
|
ALTER TABLE tbl_name ADD FULLTEXT index_name (column_list): 该语句指定了索引为
FULLTEXT , 用于全文索 引。
|
4. 索引的创建时机
4.1 适合创建索引的情况
- 主键自动建立唯一索引;
- 频繁作为查询条件的字段应该创建索引
- 查询中与其它表关联的字段,外键关系建立索引
- 单键/组合索引的选择问题,组合索引性价比更高
- 查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度
- 查询中统计或者分组字段
4.2 不适合创建索引的情况
- 表记录太少
- 经常增删改的表或者字段
- Where 条件里用不到的字段不创建索引
- 过滤性不好的不适合建索引
5. 性能分析
5.1 MySql Query Optimizer
1、Mysql中专门负责优化SELECT语句的优化器模块,主要功能:通过计算分析系统中收集到的统计信息,为客户端请求的Query提供他认为最优的执行计划(他认为最优的数据检索方式,但不见得DBA认为是最优的,这部分最耗费时间)
2、当客户端向MySQL请求一条Query,命令解析器模块完成请求分类,区别出示SELECT并转发给MySQL Query Optimizer时,MySQL Query Optimizer首先会对整条Query进行优化,处理掉一些常量表达式的预算,直接换算成常量值。并对Query中查询条件进行简化和转换,如去掉一些无用或显而易见的条件、结构调整没有Himt或Hint信息(如果有),则会读取所涉及对象的统计信息,根据Query进行写相应的计算分析,然后再得出最后的执行计划。
5.2 MySQL常见瓶颈
- CPU:CPU在饱和的时候一般发生在数据装入内存或从磁盘上读取数据时候
- IO: 磁盘I/O瓶颈发生在装入数据远大于内存容量的时候
- 服务器硬件的性能瓶颈:top,free,iostat,和vmstat来查看系统的性能状态
第 6 章 Explain 性能分析
1. 概念
能干嘛
- 表的读取顺序
- 数据读取操作的操作类型
- 哪些索引可以使用
- 哪些索引被实际使用
- 表之间的引用
- 每张表有多少行被优化器查询
![](/assets/blank.gif)
2. Explain 准备工作
CREATE TABLE t1(id INT(10) AUTO_INCREMENT,content VARCHAR(100) NULL , PRIMARY KEY (id));CREATE TABLE t2(id INT(10) AUTO_INCREMENT,content VARCHAR(100) NULL , PRIMARY KEY (id));CREATE TABLE t3(id INT(10) AUTO_INCREMENT,content VARCHAR(100) NULL , PRIMARY KEY (id));CREATE TABLE t4(id INT(10) AUTO_INCREMENT,content VARCHAR(100) NULL , PRIMARY KEY (id));INSERT INTO t1(content) VALUES(CONCAT('t1_',FLOOR(1+RAND()*1000)));INSERT INTO t2(content) VALUES(CONCAT('t2_',FLOOR(1+RAND()*1000)));INSERT INTO t3(content) VALUES(CONCAT('t3_',FLOOR(1+RAND()*1000)));INSERT INTO t4(content) VALUES(CONCAT('t4_',FLOOR(1+RAND()*1000)));
3. id
explain select t2.*
from t1,t2,t3
where t1.id = t2.id and t1.id = t3.id
and t1.content = ''
![](/assets/blank.gif)
explain select t2.*
from t2
where id = (select id
from t1
where id =(select t3.id
from t3
where t3.content = ''))
②id 不同, 如果是子查询,id 的序号会递增,id 值越大优先级越高,越先被执行
![](/assets/blank.gif)
explain select t2.* from (
select t3.id
from t3
where t3.content = '') s1, t2
where s1.id = t2.id;
![](/assets/blank.gif)
4. select_type
4.1 SIMPLE
4.2 PRIMARY
![](/assets/blank.gif)
4.3 DERIVED
4.4 SUBQUERY
4.5 DEPENDENT SUBQUERY
4.6 UNCACHEABLE SUBQUREY
![](/assets/blank.gif)
4.7 UNION
![](/assets/blank.gif)
4.8 UNION RESULT
5. table
6. type
6.1 system
6.2 const
表示通过索引一次就找到了,const 用于比较 primary key 或者 unique 索引。因为只匹配一行数据,所以很快 如将主键置于 where 列表中,MySQL 就能将该查询转换为一个常量。
6.3 eq_ref
![](/assets/blank.gif)
唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描。
6.4 ref
![](/assets/blank.gif)
建立索引后:
6.5 range
![](/assets/blank.gif)
6.6 index
6.7 all
Full Table Scan,将遍历全表以找到匹配的行。
6.8 index_merge
![](/assets/blank.gif)
6.9 ref_or_null
![](/assets/blank.gif)
6.10 index_subquery
利用索引来关联子查询,不再全表扫描。
6.11 unique_subquery
该联接类型类似于 index_subquery。 子查询中的唯一索引。
7. possible_keys
8. key
9. key_len
10. ref
显示索引的哪一列被使用了,如果可能的话,是一个常数。哪些列或常量被用于查找索引列上的值。
11. rows
rows 列显示 MySQL 认为它执行查询时必须检查的行数。越少越好!
12. Extra
12.1 Using filesort
![](/assets/blank.gif)
优化后,不再出现 filesort 的情况:
![](/assets/blank.gif)
查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度。
12.2 Using temporary
![](/assets/blank.gif)
优化后:
![](/assets/blank.gif)
12.3 Using index
12.4 Using where
12.5 Using join buffer
![](/assets/blank.gif)
使用了连接缓存。
12.6 impossible where
![](/assets/blank.gif)
12.7 select tables optimized away
![](/assets/blank.gif)
在 Myisam 中:
第 7 章 批量数据脚本
1. 插入数据
1.1 建表语句
CREATE TABLE `dept` (`id` INT(11) NOT NULL AUTO_INCREMENT,`deptName` VARCHAR(30) DEFAULT NULL,`address` VARCHAR(40) DEFAULT NULL,ceo INT NULL ,PRIMARY KEY (`id`)) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;CREATE TABLE `emp` (`id` INT(11) NOT NULL AUTO_INCREMENT,`empno` INT NOT NULL ,`name` VARCHAR(20) DEFAULT NULL,`age` INT(3) DEFAULT NULL,`deptId` INT(11) DEFAULT NULL,PRIMARY KEY (`id`)#CONSTRAINT `fk_dept_id` FOREIGN KEY (`deptId`) REFERENCES `t_dept` (`id`)) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
1.2 设置参数
![](/assets/blank.gif)
1.3 编写随机函数
1.3.1 随机产生字符串
DELIMITER $$CREATE FUNCTION rand_string(n INT) RETURNS VARCHAR(255)BEGINDECLARE chars_str VARCHAR(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';DECLARE return_str VARCHAR(255) DEFAULT '';DECLARE i INT DEFAULT 0;WHILE i < n DOSET return_str =CONCAT(return_str,SUBSTRING(chars_str,FLOOR(1+RAND()*52),1));SET i = i + 1;END WHILE;RETURN return_str;END $$
# 用于随机产生多少到多少的编号DELIMITER $$CREATE FUNCTION rand_num (from_num INT ,to_num INT) RETURNS INT(11)BEGINDECLARE i INT DEFAULT 0;SET i = FLOOR(from_num +RAND()*(to_num -from_num+1));RETURN i;END$$
1.4 创建存储过程
1.4.1 创建往 emp 表中插入数据的存储过程
DELIMITER $$CREATE PROCEDURE insert_emp( START INT , max_num INT )BEGINDECLARE i INT DEFAULT 0;#set autocommit =0 把 autocommit 设置成 0SET autocommit = 0;REPEATSET i = i + 1;
1.4.2 创建往 dept 表中插入数据的存储过程
# 执行存储过程,往 dept 表添加随机数据DELIMITER $$CREATE PROCEDURE `insert_dept`( max_num INT )BEGINDECLARE i INT DEFAULT 0;SET autocommit = 0;REPEATSET i = i + 1;INSERT INTO dept ( deptname,address,ceo ) VALUES (rand_string(8),rand_string(10),rand_num(1,500000));UNTIL i = max_numEND REPEAT;COMMIT;END$$
1.5 调用存储过程
1.5.1 添加数据到部门表
# 执行存储过程,往 dept 表添加 1 万条数据DELIMITER ;CALL insert_dept(10000);
1.5.2 添加数据到员工表
# 执行存储过程,往 emp 表添加 50 万条数据DELIMITER ;CALL insert_emp(100000,500000);
1.6 批量删除某个表上的所有索引
1.6.1 删除索引的存储过程
DELIMITER $$CREATE PROCEDURE `proc_drop_index`(dbname VARCHAR(200),tablename VARCHAR(200))BEGINDECLARE done INT DEFAULT 0;DECLARE ct INT DEFAULT 0;DECLARE _index VARCHAR(200) DEFAULT '';DECLARE _cur CURSOR FORSELECTindex_nameFROM information_schema.STATISTICSWHEREtable_schema=dbname AND table_name=tablename AND seq_in_index=1 ANDindex_name <>'PRIMARY' ;DECLARE CONTINUE HANDLER FOR NOT FOUND set done=2 ;OPEN _cur;FETCH_cur INTO _index;WHILE _index<>'' DOSET @str = CONCAT("drop index ",_index," on ",tablename );PREPARE sql_str FROM @str ;EXECUTE sql_str;DEALLOCATE PREPARE sql_str;SET _index='';FETCH_cur INTO _index;END WHILE;CLOSE _cur;END$$
1.6.2 执行存储过程
第 8 章 单表使用索引常见的索引失效
1. 全值匹配我最爱
1.1 有以下 SQL 语句
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 and deptid=4EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 and deptid=4 AND emp.name = 'abcd
1.2 建立索引
![](/assets/blank.gif)
结论:全职匹配我最爱指的是,查询的字段按照顺序在索引中都可以匹配到!
![](/assets/blank.gif)
2. 最佳左前缀法则
![](/assets/blank.gif)
3. 不要在索引列上做任何计算
不在索引列上做任何操作(计算、函数、(自动 or 手动)类型转换),会导致索引失效而转向全表扫描。
3.1 在查询列上使用了函数
![](/assets/blank.gif)
结论:等号左边无计算!
3.2 在查询列上做了转换
create index idx_name on emp(name);
|
explain select sql_no_cache * from emp where name='30000'; |
explain select sql_no_cache * from emp where name=30000; |
![](/assets/blank.gif)
结论:等号右边无转换!
4. 索引列上不能有范围查询
explain SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 and deptid=5 AND emp.name = 'abcd'; |
explain SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 and deptid<=5 AND emp.name = 'abcd'; |
建议:将可能做范围查询的字段的索引顺序放在最后
5. 尽量使用覆盖索引
explain SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 and deptId=4 and name='XamgXt';
|
explain SELECT SQL_NO_CACHE age,deptId,name FROM emp WHERE emp.age=30 and deptId=4 and name='XamgXt';
|
6. 使用不等于(!= 或者<>)的时候
7. 字段的 is not null 和 is null
当字段允许为 Null 的条件下:
is not null 用不到索引,is null 可以用到索引。
8. like 的前后模糊匹配
前缀不能出现模糊匹配!
9. 减少使用 or
使用 union all 或者 union 来替代:
10. 练习
Where 语句
|
索引是否被使用
|
---|---|
where a = 3
|
Y, 使用到 a
|
where a = 3 and b = 5
|
Y, 使用到 a , b
|
where a = 3 and b = 5 and c = 4
|
Y, 使用到 a,b,c
|
where b = 3 或者 where b = 3 and c = 4 或者
where c = 4
|
N
|
where a = 3 and c = 5
|
使用到 a , 但是 c 不可以, b 中间断了
|
where a = 3 and b > 4 and c = 5
|
使用到 a 和 b , c 不能用在范围之后, b 断了
|
where a is null and b is not null
|
is null 支持索引 但是 is not null 不支持 , 所
以 a 可以使用索引 , 但是 b 不可以使用
|
where a <> 3
|
不能使用索引
|
where abs(a) =3
|
不能使用 索引
|
where a = 3 and b like 'kk%' and c = 4
|
Y, 使用到 a,b,c
|
where a = 3 and b like '%kk' and c = 4
|
Y, 只用到 a
|
where a = 3 and b like '%kk%' and c = 4
|
Y, 只用到 a
|
where a = 3 and b like 'k%kk%' and c = 4
|
Y, 使用到 a,b,c
|
11. 口诀
第 9 章 关联查询优化
1. 建表语句
CREATE TABLE IF NOT EXISTS `class` (`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,`card` INT(10) UNSIGNED NOT NULL,PRIMARY KEY (`id`));CREATE TABLE IF NOT EXISTS `book` (`bookid` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,`card` INT(10) UNSIGNED NOT NULL,PRIMARY KEY (`bookid`));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
2. 案例
2.1 left join
2.2 inner join
②两个查询字段调换顺序,发现结果也是一样的!
③在 book 表中,删除 9 条记录
2.3 四个关联查询案例分析
EXPLAIN SELECT ed.name ' 人物 ',c.name ' 掌门 ' FROM(SELECT e.name,d.ceo from t_emp e LEFT JOIN t_dept d on e.deptid=d.id) edLEFT JOIN t_emp c on ed.ceo= c.id;
EXPLAIN SELECT e.name ' 人物 ',tmp.name ' 掌门 'FROM t_emp e LEFT JOIN (SELECT d.id did,e.name FROM t_dept d LEFT JOIN t_emp e ON d.ceo=e.id)tmpON e.deptId=tmp.did;
EXPLAIN SELECT e1.name ' 人物 ',e2.name ' 掌门 'FROM t_emp e1LEFT JOIN t_dept d on e1.deptid = d.idLEFT JOIN t_emp e2 on d.ceo = e2.id ;
Explain SELECT e2.name ' 人物 ',(SELECT e1.name FROM t_emp e1 where e1.id= d.ceo) ' 掌门 'from t_emp e2 LEFT JOIN t_dept d on e2.deptid=d.id;
结论:能够直接多表关联的尽量直接关联,不用子查询!
第 10 章 子查询优化
1. 案例
取所有不为掌门人的员工,按年龄分组!
select age as '年龄', count(*) as '人数' from t_emp where id not in
(select ceo from t_dept where ceo is not null) group by age;
此时,再次查询:
![](/assets/blank.gif)
结论: 在范围判断时,尽量不要使用 not in 和 not exists,使用 left join on xxx is null 代替。
第 11 章 排序分组优化
1. 无过滤不索引
![](/assets/blank.gif)
using filesort 说明进行了手工排序!原因在于没有 where 作为过滤条件!
![](/assets/blank.gif)
结论: 无过滤,不索引。where,limt 都相当于一种过滤条件,所以才能使用上索引!
2. 顺序错,必排序
![](/assets/blank.gif)
②explain select * from emp where age=45 order by deptid,empno;
![](/assets/blank.gif)
![](/assets/blank.gif)
deptid 作为过滤条件的字段,无法使用索引,因此排序没法用上索引
3. 方向反,必排序
![](/assets/blank.gif)
如果排序的字段,顺序有差异,就需要将差异的部分,进行一次倒置顺序,因此还是需要手动排序的!
4. 索引的选择
①首先,清除 emp 上面的所有索引,只保留主键索引!
drop index idx_age_deptid_name on emp;
![](/assets/blank.gif)
![](/assets/blank.gif)
5. using filesort
5.1 mysql 的排序算法
5.2 如何优化
6. 使用覆盖索引
![](/assets/blank.gif)
7. group by
![](/assets/blank.gif)
第 12 章 练习
1. 案例一
select e1.name empname,e1.age empage,e2.name ceoname,e2.age ceoagefrom t_emp e1 inner join t_dept d on e1.deptid=d.idinner join t_emp e2 on d.ceo=e2.idwhere e1.age>e2.age;
![](/assets/blank.gif)
更换为大表,进行分析:
explain select e1.name empname,e1.age empage,e2.name ceoname,e2.age ceoage from emp e1 inner join dept d one1.deptid=d.idinner join emp e2 on d.ceo=e2.idwhere e1.age>e2.age;
![](/assets/blank.gif)
两次 inner join 的被驱动表都已经用上了索引。
2. 案例二
select e1.name from t_emp e1inner join(select deptid,AVG(age) avgage from t_empgroup by deptid) tmpon e1.deptid=tmp.deptidwhere e1.age<tmp.avgage;
![](/assets/blank.gif)
更换为大表:
explain select e1.name from emp e1inner join(select deptid,AVG(age) avgage from empgroup by deptid) tmpon e1.deptid=tmp.deptidwhere e1.age<tmp.avgage;
![](/assets/blank.gif)
![](/assets/blank.gif)
3. 案例三
select d.deptName,count(*)from t_emp e inner join t_dept don e.deptid=d.idwhere e.age>40group by d.id,d.deptNamehaving count(*)>=2
![](/assets/blank.gif)
大表优化:
explain select d.deptName,count(*)from emp e inner join dept don e.deptid=d.idwhere e.age>40group by d.id,d.deptNamehaving count(*)>=2
4. 案例四
select d2.deptName from t_emp e inner join t_dept d2 on e.deptid=d2.idleft join t_dept d on e.id=d.ceowhere d.id is null and e.deptid is not nullgroup by d2.deptName,d2.idhaving count(*)>=2;
explain select d2.deptName from emp e inner join dept d2 on e.deptid=d2.idleft join dept d on e.id=d.ceowhere d.id is null and e.deptid is not nullgroup by d2.deptName,d2.idhaving count(*)>=2;
![](/assets/blank.gif)
5. 案例五
![](/assets/blank.gif)
大表关联:
explain select e.name,case when d.id is null then ' 否 ' else ' 是 ' end ' 是否为掌门 ' from emp eleft join dept don e.id=d.ceo;
优化:在 d 表的 ceo 字段建立索引即可!
6. 案例六
select d.deptName,if(avg(age)>40,' 老鸟 ',' 菜鸟 ') from t_emp e inner join t_dept don d.id=e.deptid group by d.deptName,d.id
切换大表:
explain select d.deptName,if(avg(age)>40,' 老鸟 ',' 菜鸟 ') from dept d inner join emp eon d.id=e.deptidgroup by d.deptName,d.id
7. 案例七
select * from t_emp einner join(select deptid,max(age) maxagefrom t_empgroup by deptid) tmpon tmp.deptid=e.deptid and tmp.maxage=e.age;
大表优化:
explain select * from emp einner join(select deptid,max(age) maxagefrom empgroup by deptid) tmpon tmp.deptid=e.deptid and tmp.maxage=e.age;
第 13 章 截取查询分析
1. 慢查询日志
1.1 是什么
1.2 怎么用
SQL 语句
|
描述
|
备注
|
---|---|---|
SHOW VARIABLES LIKE '%slow_query_log%';
|
查看慢查询日志是否开启
|
默认情况下 slow_query_log 的值为 OFF ,
表示慢查询日志是禁用的
|
set global slow_query_log=1;
|
开启慢查询日志
|
|
SHOW VARIABLES LIKE 'long_query_time%';
|
查看慢查询设定阈值
|
单位秒
|
set long_query_time=1
|
设定慢查询阈值
|
单位秒
|
[mysqld]slow_query_log=1slow_query_log_file=/var/lib/mysql/atguigu-slow.loglong_query_time=3log_output=FILE
1.2 日志分析工具 mysqldumpslow
(2) 查看mysqldumpslow的帮助信息
得到返回记录集最多的 10 个 SQLmysqldumpslow -s r -t 10 /var/lib/mysql/atguigu-slow.log得到访问次数最多的 10 个 SQLmysqldumpslow -s c -t 10 /var/lib/mysql/atguigu-slow.log得到按照时间排序的前 10 条里面含有左连接的查询语句mysqldumpslow -s t -t 10 -g "left join" /var/lib/mysql/atguigu-slow.log另外建议在使用这些命令时结合 | 和 more 使用 ,否则有可能出现爆屏情况mysqldumpslow -s r -t 10 /var/lib/mysql/atguigu-slow.log | more
2. SHOW PROCESSLIST
1.1 是什么
1.2 怎么用
第 14 章 工具和技巧拾遗
1.1 是什么
1.2 作用
第 15 章 主从复制
1.1 复制的基本原理
1.2 复制的基本原则
1.3 复制的最大问题
1.4 一主一从常见配置
主服务器唯一 ID
server-id=1启用二进制日志 JAVAEE 课程系列log-bin= 自己本地的路径 /data/mysqlbinlog-bin=D:/devSoft/MySQLServer5.5/data/mysqlbin设置不要复制的数据库binlog-ignore-db=mysql设置需要复制的数据库binlog-do-db= 需要复制的主数据库名字设置 logbin 格式binlog_format=STATEMENT (默认)
mysql 主从复制起始时,从机不继承主机数据
# 从机服务 idserver-id = 2# 注意 my.cnf 中有 server-id = 1# 设置中继日志relay-log=mysql-relay
(5) 因修改过配置文件,请主机+从机都重启后台 mysql 服务
# 创建用户,并授权GRANT REPLICATION SLAVE ON *.* TO ' 备份账号 '@' 从机器数据库 IP' IDENTIFIED BY '123456';
(8) 查询 master 的状态,并记录下 File 和 Position 的值
# 查询 master 的状态show master status;
执行完此步骤后不要再操作主服务器 MYSQL,防止主服务器状态值变化
# 查询 master 的状态CHANGE MASTER TO MASTER_HOST=' 主机 IP',MASTER_USER=' 创建用户名 ',MASTER_PASSWORD=' 创建的密码 ',MASTER_LOG_FILE='File 名字 ',MASTER_LOG_POS=Position 数字 ;
(10) 启动从服务器复制功能
start slave;show slave status\G;
下面两个参数都是 Yes,则说明主从配置成功!
Slave_IO_Running: YesSlave_SQL_Running: Yes
(11) 主机新建库、新建表、insert 记录,从机复制
stop slave;
第 16 章 MYCAT
1.1 是什么
数据库中间件,前身是阿里的 cobar
1.2 做什么
- 读写分离
- 数据分片:
垂直拆分、水平拆分
垂直+水平拆分
3.多数据源整合
1.3 MYCAT 原理
“拦截”:Mycat 的原理中最重要的一个动词是“拦截”,它拦截了用户发送过来的 SQL 语句,首先对 SQL 语句做了一些特定的分析:如分片分析、路由分析、读写分离分析、缓存分析等,然后将此 SQL 发往后端的真实数据库,并将返回的结果做适当的处理,最终再返回给用户。
这种方式把数据库的分布式从代码中解耦出来,程序员察觉不出来后台使用 mycat 还是 mysql。
1.4 安装启动
- 解压缩文件拷贝到 linux 下 /usr/local/
- 三个配置文件
schema.xml 定义逻辑库,表、分片节点等内容 rule.xml 定义分片规则
server.xml 定义用户以及系统相关变量,如端口等.
3.启动前先修改 schema.xml
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/"><!--逻辑库 name 名称, checkSQLschema sqlMaxLimit 末尾是否要加 limit xxx-->
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"> </schema><!--逻辑库 name 名称, dataHost 引用的哪个 dataHost database:对应 mysql 的 database-->
<dataNode name="dn1" dataHost="localhost1" database="db1" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"writeType="0" dbType="mysql" dbDriver="native" switchType="1"
slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!-- can have multi write hosts --><writeHost host="hostM1" url="localhost:3306" user="root"
password="123456"></writeHost>
</dataHost>
</mycat:schema>
4. 再修改 server.xml
<user name="root">
<property name="password">654321</property>
<property name="schemas">TESTDB</property>
</user>
5. 启动程序
控制台启动 :去 mycat/bin 目录下 mycat console 后台启动 :去 mycat/bin 目录下 mycat start
6.启动时可能出现报错
域名解析失败
用 vim 修改 /etc/hosts 文件,在 127.0.0.1 后面增加你的机器名
修改后重新启动网络服务
7. 后台管理窗口登录
MySQL高级--个人笔记相关推荐
- Mysql 高级学习笔记
Mysql 高级学习笔记 文章目录 Mysql 高级学习笔记 一.Mysql 基础 1. 聚合函数 2. having 3. sql 的执行顺序 4. 约束 5. 试图 二.Mysql 高级 1. M ...
- MySQL高级学习笔记(四)
文章目录 MySQL高级学习笔记(四) 1. MySql中常用工具 1.1 mysql 1.1.1 连接选项 1.1.2 执行选项 1.2 mysqladmin 1.3 mysqlbinlog 1.4 ...
- 【MySQL高级篇笔记-MySQL事务日志(下) 】
此笔记为尚硅谷MySQL高级篇部分内容 目录 一.redo日志 1.为什么需要REDO日志 2.REDO日志的好处.特点 3.redo的组成 4.redo的整体流程 5.redo log的刷盘策略 6 ...
- 尚硅谷MySQL高级学习笔记 -- 1.MySQL 的架构介绍
1.MySQL 简介 什么是 MySQL? MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,目前属于Oracle公司. MySQL是一种关联数据库管理系统,将数据保存在不同的表中 ...
- 尚硅谷MySQL高级学习笔记
数据库MySQL学习笔记高级篇 文章目录 数据库MySQL学习笔记高级篇 写在前面 1. mysql的架构介绍 mysql简介 概述 高级Mysql mysqlLinux版的安装 mysql配置文件 ...
- mysql高级学习笔记
索引 帮助mysql高效获取数据的数据结构 缺点:降低了更新表的效率,增加了磁盘开销. B树和B+树 m叉的B数每个节点最多包含m-1个key,而B+数最多m个key B+树的叶子节点保存了所有的ke ...
- 三、Mysql高级学习笔记之EXPLAN
Mysql Explain 1.是什么 使用EXPLAIN关键字可以模拟优化器执行SQL语句,从而知道MySQL是 如何处理你的SQL语句的.分析你的查询语句或是结构的性能瓶颈 2.能干嘛 1.表的读 ...
- mysql高级篇(二)mysql索引优化分析
mysql高级篇笔记 mysql高级篇(一)mysql的安装配置.架构介绍及SQL语句的复习. mysql高级篇(二)mysql索引优化分析. mysql高级篇(三)查询截取分析(慢查询日志).主从复 ...
- mysql高级笔记_MySQL高级部分笔记
有关于MySQL的高级部分笔记 这是一篇关于MySQL高级部分的笔记主要是,sql优化以及mysql锁的相关内容,以及主从配置等内容等比较基础的优化 一.逻辑架构部分 逻辑架构 逻辑架构介绍图如下 连 ...
最新文章
- iOS高级面试之NSRunLoop须知
- 一起谈.NET技术,ASP.NET MVC2实现分页和右键菜单
- C#SetWindowPos窗口置顶
- java中arges.length_java中的args.length
- win10共享打印错误0x0000006_Win7打印机无法共享提示错误代码0x000006d9的解决方法...
- Light OJ 1078
- 基于python的证件照_用20行python代码给证件照换底色
- 网站选择按钮点击无反应?_Win10系统电脑鼠标左键单击没有反应的解决办法
- 数据可视化的十大优点
- 主机字节序和网络字节序(大端序,小端序,网络序)
- Winsw将jar包部署为windows服务
- 认识影片版本(CAM、TS、TC、DVD、HD、BD、TVRIP等)
- 暂时初步完成了搜索引擎的基本功能
- 连载IT小说《失业的程序员》讲述一个Android开发者的奋斗史
- 素数五个为一行的_帕斯卡三角形与素数
- 在火狐浏览器打开xpath_Firefox火狐插件firebug和xpath checker提取关键词
- MC74HC595驱动
- Python(28)---模块和包的基本概念
- MP3解码流程(一)-----音频文件结构解析
- iOS设备 历代 机型对照表
热门文章
- Tomcat服务器启动Bug:Error running ‘Tomcat 9.0.37‘: Address localhost:1099 is already in use
- 设计模式笔记之三抽象工厂模式
- if x 和 if x is not None的区别(python)
- Pvcreate 创建物理卷
- ps 2023(24.7beta) mac
- 安贫乐道 = 心态好
- 原码补码反码范围对比图
- php curl nginx 499 错误
- 关于mysql错误的是_下面关于MySQL描述错误的是( )。_学小易找答案
- DELL戴尔外星人笔记本电脑Alienware m18 R1原装出厂Win11系统恢复原厂OEM系统