《深入浅出Mysql》阅读梳理 五

点击查看合集

优化SQL

第一步

通过show status 命令了解更重SQL语句的执行频率

第二步

定位执行效率较低的SQL语句
方法1:通过慢查询日志定位那些执行效率较低的SQL语句。将slow-query-log参数设置为ON后,MySQL会将所有执行时间超过阈值的SQL,写入slow_quert_log_file参数所指定的文件中。
方法2:方法1只有执行后才会写入日志文件。通过show processList命令可以查看当前正在执行的线程,可以实时查看sql的执行情况

第三步

分析SQL
方法1:通过Explain命令分析低效SQL的执行计划
方法2:用show profile for query Id (id 可以通过show profiles 获取)查看sql语句具体执行过程中,不同过程所需要的时间。
方法3:通过trace分析优化器如何选择执行计划

优化SQL的原则

1.小表驱动大表
2.order by 尽量使用索引顺序排序
3.

Select * from A where A.id in (select B.id from B)#B表驱动A表,相当于先从B表中查出id,然后再在A表中循环匹配(最好B是小表 (驱动表))

Select * from A where exists(select 1 from B where A.id = B.id)# A表驱动B表,相当于先从A表中查找数据,然后再利用B表过滤数据(最好A是小表 (驱动表))

慢查询日志

慢查询日志可以记录sql执行时间超过阈值的记录。默认情况下慢查询日志是关闭的需要手动开启。不过只有在需要的时候才开启,不需要的时候不要开启。因为开启后会带来一定的性能影响。
在这里插入图片描述

set global slow_query_log = on

通过这条语句可以开启慢查询日志。但是这只是开启当前数据库在此时的慢查询日志。服务器重启后失效。
如果想要永久生效,则需要去mysql的配置文件进行配置

查看超过多少秒会被认为是慢sql

show VARIABLES like '%long_query_time%' # 查看慢查询日志记录的阈值

在这里插入图片描述
即大于10s的sql是慢sql。

set global long_query_time = 1 #设置阈值为1秒
select sleep(2)

在这里插入图片描述
注意:需要重新连接mysql这个阈值才会更改。

mysqldumpslow

mysqldumpslow是mysql提供的一个工具,它可以帮助我们更好的分析慢查询日志文件。

索引

索引:排好序的快速查找数据结构
索引类型
在这里插入图片描述
InnoDB子啊MySQL 5.7中支持自适应的Hash索引。所谓自适应就是,Mysql根据数据的访问频率和模式为某些热点页自动创建Hash索引,索引由buffer pool中的B_tree来自动生成,效率很高。Hash索引适用于key-value查询。当使用范围查询时Hash索引不起作用。

MysQL如何使用索引

B-Tree索引时最常见的索引,构造类似二叉树,但却不是二叉树。B-Tree的B不是二叉树的意思而是平衡的意思。B-Tree索引可以很好的用于全关键字,关键字范围,关键字前缀的查询。
B-Tree的结构
在这里插入图片描述
根节点root下面有多个分支(Branch节点)。Branch节点下面得就是明细叶子(Leaf节点)

什么时候建索引

1.主键自动创建唯一索引
2.频繁作为查询条件的字段
3.查询中与其他表关联的字段,外键关系建立索引
4.查询中排序的字段
5.查询中统计或者分组的字段

什么时候不用索引

1.where条件里用不到的字段
2.频繁更新的字段
3.

防止索引失效

最左匹配原则

如果使用了复合索引,那么索引的顺序很重要。使用索引的顺序要和创建索引的顺子一致(如果写的乱序也可以,因为myslq的优化器会把他优化成正序),之间不能缺少索引。否则复合索引不能完全使用到。首先第一个索引不能丢。后面的索引在哪断了那么后面的索引就都不起作用了,但是前面的依然有效。(这是和索引的数据结构B-Tree有关)

不要对索引进行操作

不要对索引进行操作,因为这样就不能再利用索引了。如使用left(索引列,n)函数.就会变成不精确的查询,不精确的查询会使索引列失效。

范围右侧的索引全失效

这个顺序是指创建的顺序,因为sql语句中的顺序会被优化器优化成最优的顺序(mysql 8是这样的)例子

explain select * from test19 where   id3 = 1 and id2 > 2 and id1 = 1 

在这里插入图片描述

explain select * from test19 where   id2 = 1 and id3 > 2 and id1 = 1 

在这里插入图片描述

我创建的索引是一个(id1 id2 id3)顺序的复合索引。当我用id2进行范围查询时id3的索引失效了。

尽量使用覆盖索引

进项不使用select * 如果要检索不在索引内的字段时,会回表。

explain select * from test19 where   id3 = 1 and id2 > 2 and id1 = 1 

在这里插入图片描述

explain select id1,id2,id3 from test19 where   id3 = 1 and id2 > 2 and id1 = 1

在这里插入图片描述

但是我有一个疑问这俩type一个是index一个是range。讲道理range是在索引中进行范围查询,而index是扫描全部的索引。不是应该range更好么。(我使用复合索引的时候出现了这种情况。如果我不适用复合索引,只是使用普通索引,那么type都是range)

使用!=会使索引失效(mysq8 会用到索引)

如果是mysql8版本的话,同样会用到索引

explain select id1 from test19 where  id1 !=1

在这里插入图片描述

explain select * from test19 where  id1 !=1

在这里插入图片描述
如果我使用普通索引,那么type都是range

is (not) null无法使用索引(mysql 8 可以使用索引)

以下例子都是mysql8的

explain select * from test18 where  id1 is null

在这里插入图片描述

模糊查询不能以%开头

explain select * from user where username like "name%"

在这里插入图片描述

explain select * from user where username like "%name"

在这里插入图片描述
但是如果非要使用%开头的话,可以使用下列解决方法
通过使用覆盖索引的方式

explain select username from user where username like "%name"

在这里插入图片描述

explain select password from user where username like "%name" # 非selet 覆盖索引

在这里插入图片描述

查找主键

explain select id from user where username like "%name"

在这里插入图片描述

防止索引列的类型转换

explain select username from user where username = '11'

在这里插入图片描述

explain select username from user where username = 11; 

在这里插入图片描述

少用or(mysql 8 or不会使索引失效)

mysql 8不会使索引失效

explain select password from user where username = '11' or username  ='1'; 

在这里插入图片描述

explain select password from user where username = '11' or username  ='1'; 

Explain

Explain +SQL语句。
在这里插入图片描述
查询后会显示这些字段。通过这些字段可以知道
1.表的读取顺序
2.数据读取操作的操作类型
3.显示这一行的数据是关于哪张表的
4.显示查询使用了何种类型
5.可能使用的索引

6.真正使用的索引
7.显示与索引列进行等值匹配的字段
8.估算出要找到所需记录需要读取的行数(越少越好)

id (可以获得表的读取顺序)

	explain select * from test16 ,test15,test14

在这里插入图片描述

当id相同时时,执行顺序为从上至下。即先查询test16表然后是test15 最后是test14

EXPLAIN SELECT
	* 
FROM
	test16 t16 
WHERE
	t16.id = (
	SELECT
		t15.id 
	FROM
		test15 t15 
WHERE
	t15.id = ( SELECT t14.id FROM test14 t14 ))

在这里插入图片描述

如果是子查询那么id会递增,id越大越先执行。

EXPLAIN SELECT
	* 
FROM
	test16 t16 , test17
WHERE
	t16.id = (
	SELECT
		t15.id 
	FROM
		test15 t15 
WHERE
	t15.id = ( SELECT t14.id FROM test14 t14 ))

当既有相同id又有不同id时。先执行最大的。然后相同的按顺序执行。

Select_type(数据读取操作的操作类型)

1.Simple:简单的select查询,不包含子查询和union
2.Primary:若查询中包含任何复杂的子部分,最外层查询则被标记为Primary
3.SubQuery:在select或where糙汉子查询
4.Derived:在from列表中包含的子查询被标记为Derived(衍生),Mysql会递归执行这些子查询,把结果放在临时表里。
5.Union:若第二个select出现在union之后,则被标记为union。若union包含在from字句的子查询中,外层select被标记未Derived
6.union Result:从Union表获取结果的select
例子

EXPLAIN SELECT
	* 
FROM
	( SELECT * FROM test15 UNION SELECT * FROM test14 ) ss,
	test16 
WHERE
	ss.id = test16.id

在这里插入图片描述

table(操作的表名)

显示这一行的数据是关于哪张表的

type(显示查询使用了何种类型)

1.System:表只有一行记录(等于系统表),这是const类型的特例
2.Const:表示通过索引一次就找到了。const常用于比较唯一索引和主键索引。因为只匹配一行数据,所以很快。
3.eq_ref:唯一性索引扫描,对于每个索引键。表中只有一条记录与之匹配。常见于主键或唯一索引扫描
4.ref:非唯一性索引扫描,返回匹配某个单独值得所有行
从最好到最差
5.range:只检索给定范围的行,使用一个索引来选择行。(> < between)
6:index:全索引扫描
7:all:全表扫描
System>Const>eq_ref>ref>range>index>all

possible_keys(可能使用的索引)

显示可能应用到的索引,可能没有,可能有一个可能有多个。查询涉及到的字段上若存在索引,则该索引将被列出。

key(真正使用的索引)

实际中使用的索引,如果为NULL则没有使用索引。查询中若使用了覆盖索引,则该索引仅出现在key列表中。
覆盖索引:索引中包含(覆盖)我们需要查询的值

key_len(索引中使用的字节数)

表示了使用到的索引的长度。如果索引类型为int 那么key_len = 5(因为允许null 所以4+1) 如果时int not null 那么此时的key_len = 4

ref(显示与索引列进行等值匹配的字段)

显示与索引进行等值查询的字段,可能是某一列也可能是某个常量(const)

rows(估算出要找到所需记录需要读取的行数)

根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数。

extra(包含不适合在其他列中显示但十分重要的额外信息)

1.Using filesort: mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。mysql中无法利用索引完成的排序操作被称为文件排序
2. Using tempoary:使用了临时表保存中间结果,mysql对查询结果排序时使用了临时表。常见于order by 和group by
3.Using index:表明select字段使用了覆盖索引
4.Using Where:使用了where进行过滤
5.Using join buffer:连接表使用了join缓存
6.impossible where:where子句肯定是false

直方图

mysql8中加入了直方图,为优化sql提供了新的思路。直方图一般用于那些没有创建索引同时数据的唯一值有限,并且数据量分布不均的表中。虽然通过创建索引的方式也可以提高访问速度,但是如果这个字段的索引使用频率不高,但是又要负担很大的维护成本。此时通过创建直方图的方式可以大大降低维护成本,直方图只需要创建一次,不需要进行实时维护。
语句。直方图之所以可以提高访问速度,是因为通过直方图mysql的优化器可以更好的选择sql的执行策略。

Analyze table table_name update histogram on table_clomun

MyISam的表级锁

MyIsam支持表级锁。表级锁分为两种一种为共享读锁一种为独占写锁。MyISam引擎认为写操作比读操作更重要,因此即使锁的等待队列中存在读锁,写锁也会排在他的前面。因此MyISam不适合有大量更新和读取操作的系统。但是在一些特殊情况下也允许在读的同时进行插入。(需要对concurrent_insert参数进行设置)当concurrent_insert参数为0时。不允许读的时候插入。当为1时,允许中间没有空洞时向表的尾部插入。当为3时,允许有空洞时向尾部插入。

MySQL的行锁

1.innoDB的行锁是基于索引实现的,如果不通过索引访问数据,innodb会对所有数据加锁
2.在不同隔离级别下InnoDB的锁机制和一致性读策略不同
在这里插入图片描述

3.MySQL的恢复和复制对InnoDB锁机制和一致性读策略也有较大影响。
4.锁冲突甚至死锁很难完避免。

//主从复制

猜你喜欢

转载自blog.csdn.net/qq_30033509/article/details/114500398
今日推荐