MySQL高级之索引优化分析

MySQL高级之索引优化分析

  • 一、索引优化分析
    • 1、SQL性能下降
    • 2、常见通用的Join查询
    • 3、索引简介
      • A.是什么?
      • B.优势
      • C.缺点
      • D.MySQL索引分类
      • E.MySQL索引结构
      • F.哪些情况需要创建索引
      • G.哪些情况不需要创建索引
    • 4、性能分析
    • 5、索引优化
      • A.索引分析
      • B.索引失效(应该避免)
      • C.一般性建议

一、索引优化分析

1、SQL性能下降

原因)执行时间长
没有索引、索引失效(单值索引、复合索引)、关联查询太多join(设计缺陷或不得已的需求)、服务器调优以及各个参数设置(缓冲、线程数等)
索引原理)值顺序重新调整过,而不是杂乱无章的,所以查询的时候查询的更快。
例)
select * from user where name=? and password=?
create index idx_user_namePassword on user(name,password)

2、常见通用的Join查询

1)SQL执行顺序,
MySQL高级之索引优化分析_第1张图片
MySQL高级之索引优化分析_第2张图片
2)7种JOIN,

#最基本的四种
SELECT
	* 
FROM
	tableA A
	LEFT JOIN tableB B ON A.KEY = B.KEY;
	
SELECT
	* 
FROM
	tableA A
	INNER JOIN tableB B ON A.KEY = B.KEY;
	
SELECT
	* 
FROM
	tableA A
	RIGHT JOIN tableB B ON A.KEY = B.KEY;
	
SELECT
	* 
FROM
	tableA A
	FULL OUTER JOIN tableB B ON A.KEY = B.KEY;
#三种变形
SELECT
	* 
FROM
	tableA A
	LEFT JOIN tableB B ON A.KEY = B.KEY 
WHERE
	B.KEY IS NULL;
	
SELECT
	* 
FROM
	tableA A
	RIGHT JOIN tableB B ON A.KEY = B.KEY 
WHERE
	A.KEY IS NULL;
	
SELECT
	* 
FROM
	tableA A
	FULL OUTER JOIN tableB B ON A.KEY = B.KEY 
WHERE
	A.KEY IS NULL 
	OR B.KEY IS NULL;

注:MySQL不支持Full outer,可以用去重的union来做

/*
SELECT
	* 
FROM
	tableA A
	RIGHT JOIN tableB B ON A.KEY = B.KEY 
WHERE
	A.KEY IS NULL;
*/
SELECT
	* 
FROM
	tableA A
	LEFT JOIN tableB B ON A.KEY = B.KEY
	
UNION

SELECT
	* 
FROM
	tableA A
	RIGHT JOIN tableB B ON A.KEY = B.KEY
/*
SELECT
	* 
FROM
	tableA A
	FULL OUTER JOIN tableB B ON A.KEY = B.KEY 
WHERE
	A.KEY IS NULL 
	OR B.KEY IS NULL;
*/
SELECT
	* 
FROM
	tableA A
	LEFT JOIN tableB B ON A.KEY = B.KEY 
WHERE
	B.KEY IS NULL 
	
UNION

SELECT
	* 
FROM
	tableA A
	RIGHT JOIN tableB B ON A.KEY = B.KEY 
WHERE
	A.KEY IS NULL

3、索引简介

A.是什么?

索引是为了帮助MySQL高效获取数据的一种数据结构。一般都指多路平衡搜索树–B树。而聚集索引、次要索引、覆盖索引、复合索引、前缀索引、唯一索引都默认使用B+树。除此之外,还有hash index。
MySQL高级之索引优化分析_第3张图片
注:col1是记录数据地址的指针。
注:一般来说索引也非常大,就不可能全部存在内存之中,所以索引往往以索引文件的形式存储在磁盘上。
注:索引可以影响where后的索引字段约束和order by 后的索引字段两大部分。

B.优势

1)提高数据检索效率,降低数据库的IO成本。
2)通过索引列对数据进行排序,此时就降低了排序成本,减少CPU的消耗。

C.缺点

1)索引占空间,每对一个字段建一个单值索引,就有一张表保存了主键与索引字段,并指向实体表的记录。
2)提高了查询速度,但是在更新记录时需维护索引结构。
3)索引只是提高查询效率的一种方式,而需要我们研究建立最优秀的索引。

D.MySQL索引分类

1)单值索引,一个索引只包含单个列,一个表可以有多个单列索引。
注:一般建复合索引,一般一张表建的索引不超过5个。
2)唯一索引,索引列的值必须唯一,但允许有空值。
3)复合索引,一个索引包含多个列。
4)基本语法,

#创建
CREATE [ UNIQUE ] INDEX indexName ON myTable ( columnName ( length ) ) 
ALTER myTable ADD [ UNIQUE ] INDEX [ indexName ] ON ( columnName ( length ) )
#删除
DROP INDEX [ indexName ] ON myTable;
# 查看
SHOW INDEX 
FROM
	table_name \G

MySQL高级之索引优化分析_第4张图片

E.MySQL索引结构

1)BTree索引

MySQL高级之索引优化分析_第5张图片

2)Hash索引
3)full-text全文索引
4)R-Tree索引

F.哪些情况需要创建索引

1)主键自动建立唯一索引
2)频繁作为查询条件的字段应该创建索引
3)外键关系建立索引
4)需要排序的字段
5)查询中统计或者分组字段

G.哪些情况不需要创建索引

1)频繁更新的字段不适合建立索引。
2)where条件用不到的字段不需要建立索引。
3)表记录太少。大于300万建。
4)数据重复且分布平均的表字段。
MySQL高级之索引优化分析_第6张图片

4、性能分析

1)MySQL Query Optimizer
为客户端请求的Query 进行优化,但这种优化完的检索方式并不一定是最优的。
2)MySQL 常见瓶颈
CPU:CPU饱和发生在数据装入内存或从磁盘上读取数据的时候。
IO:装入数据远大于内存容量。
服务器硬件性能瓶颈,top、free、iostat、vmstat来查看系统性能的状态。
3)Explain,查看执行计划。
是什么?,查看执行计划,模拟优化器执行SQL查询语句,进而分析查询语句或是表结构的性能瓶颈。
能干嘛?
1)表的读取顺序
2)数据读取操作的操作类型
3)哪些索引可以使用
4)哪些索引被实际使用
5)表之间的引用
6)每张表有多少行被优化器查询
怎么用?
explain + SQL
字段名解释
1)id
select查询的序列号,表示查询中执行select子句或操作表的顺序。(可理解成一种优先级等级)
三种情况,
id相同,执行顺序由上到下;
id不同,如果是子查询,id的序号会自增,id值越大优先级越高,越先被执行;
id相同和不同同时存在,id相同的分为一组,从上到下顺序执行。在所有组中,id越大,优先级越高,越先被执行。derived(id)表示来源于那个id的衍生表。
2)select_type

有simple、primary、subQuery、derived、union、union、result,用于区分普通查询、联合查询、子查询等的复杂查询。

simple,简单的select查询,查询中不包括子查询或者union。

primary,查询中有查询中有复杂的子查询时,标记最外层查询为primary(最后加载哪一个)

subQuery,标记在select或where列表中的子查询。

derived,在from列表中包含的子查询被标记为衍生表,MySQL会递归执行这些子查询,把结果放在临时表中。

union,出现在union后的select查询语句,若union包含在from子句的子查询中,外层select将会标记为derived
union result,从union表获取结果的select
3)table,显示这一行数据是关于那种表的。
4)type,有8种值,显示查询使用了何种类型,有all、index、range、ref、eq_ref、const、system、null。按SQL查找好坏排序如下,system > const > eq_ref > ref > range > index > all

system,表只有一行记录(等于系统表,MySQL出厂带的表),这是const类型的特例,平时不会出现。

const,表示通过索引一次就找到了,const用于比较primary key或unique索引。因为只匹配一行数据,所以很快。如将主键id = 1写死,只有一条记录符合。
MySQL高级之索引优化分析_第7张图片
eq_ref,唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描。CEO只有一个,总裁办的一个,它也是员工,注意下面的all,需要一个表来驱动,所以秉着小表驱动大表。
MySQL高级之索引优化分析_第8张图片
ref,非唯一性索引扫描,返回匹配某个单独值的所有行。本质上也是一种索引访问,返回所有匹配某个单独值的行,然而,它可能找到多个符合条件的行,所以它应该属于查找和扫描的混合体。
MySQL高级之索引优化分析_第9张图片
注:col1 = 'ac’的很多。

range,只检索给定范围的行,使用一个索引来选择行。key列显示了使用了那个索引,一般就是where后面出现between、> 、< 、in等查询。这种范围扫描比全表扫描要好,因为它只需要开始于索引的某一点,而结束语另一点,不用扫描全部索引。
MySQL高级之索引优化分析_第10张图片
index,Full index scan,index与all的区别为index类型只遍历索引树。通常比all快,因为一般数据文件比索引文件大。(all和index都是读全表,但index是从索引中读取的,而all是从硬盘中读取的。)
注:部分情况下,内存就加载了索引。
MySQL高级之索引优化分析_第11张图片
all,full table scan,遍历全表以找到匹配的行。

注:保证查询至少达到range级别,最好能达到ref。
5)possible_keys
显示可能应用在这张表中的索引,一个或多个。查询涉及到的字段上,若存在索引,则该索引将被列出,但不一定被查询实际使用。
6)key
实际使用到的索引,如果为null,则没有使用索引。查询中若使用了覆盖索引,则该索引仅出现在key列表中。
MySQL高级之索引优化分析_第12张图片
7)key_len
表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度。在不损失精确度的情况下,长度越短越好。
注:其显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的。
MySQL高级之索引优化分析_第13张图片
8)ref
显示索引的那一列被使用了,如果可能的话,是一个常数。哪些列或常量被用于查找索引列上的值。
MySQL高级之索引优化分析_第14张图片

9)rows
根据表统计信息及索引选用情况,大致估算出找到所需记录所要读取的行数。
MySQL高级之索引优化分析_第15张图片

10)Extra,十分重要的额外信息。

**Using filesort,**MySQL会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。MySQL中无法利用索引完成的排序操作称之为“文件排序”。
MySQL高级之索引优化分析_第16张图片

Using temporary,
使用了临时表保存了中间结果,MySQL在对查询结果排序时使用了临时表,常见于排序order by 和分组查询group by。
MySQL高级之索引优化分析_第17张图片
注:有group by时,要么不建索引,要么group by后面按顺序接复合索引的字段。

Using index,
表示相应的select中使用了覆盖索引,避免访问了表的数据行,效率不错。如果同时出现using where,表示索引被用来执行索引键值的查找。否则表示索引用来读取数据而非执行查找操作。(select 列表中还是where列表中的区别。)
MySQL高级之索引优化分析_第18张图片
注:覆盖索引,表示要select的数据列只需从索引中就能获得,不必再去读取数据行文件,查询列要被所建的索引字段覆盖。
注:将所有字段一起做索引会导致索引文件过大,查询性能下降。

Using where,表明使用了where过滤。

Using join buffer,使用了连接缓存

impossible where,where字句的值总是false,不能用来获取任何数据。
在这里插入图片描述

select tables optimized away,在没有group by子句的情况下,基于索引优化MIN/MAX操作或者对于MyISAM存储引擎优化count(*)操作,不必等到执行阶段再进行计算,查询执行计划生成的阶段即完成优化。

distinct,优化distinct操作,在找到第一个匹配成功的数据时即停止找同样值的动作。
热身case
MySQL高级之索引优化分析_第19张图片
MySQL高级之索引优化分析_第20张图片

5、索引优化

A.索引分析

1)单表
MySQL高级之索引优化分析_第21张图片

#原始SQL
select id,author_id from article where category_id = 1 and comments > 1 order by views desc limit 1;

分析结果,
在这里插入图片描述
优化是必须的,why?因为type = all,Extra还出现了using filesort.
如何优化?

#改变type=all为type=range
create index idx_article_ccv on article(categroy_id,comments,views); 

在这里插入图片描述

#该索引不够好,还是有using filesort,因为views在索引的最后面,底层先对comments排序,自然会导致views索引失效。
drop index idx_article_ccv on article
create index idx_article_cv on article(categroy_id,views)

在这里插入图片描述
2)双表
MySQL高级之索引优化分析_第22张图片
MySQL高级之索引优化分析_第23张图片
MySQL高级之索引优化分析_第24张图片
MySQL高级之索引优化分析_第25张图片

注:左连接特性,左表全都有,left join 条件是限定右表的,所以索引建在右表上。

3)三表,在上面的基础上,加一个phone表,外键关联card。
MySQL高级之索引优化分析_第26张图片

#三表查询
select * from class left join book on class.card = book.card left join phone on book.card = phone.card;

给book和phone的card都建立索引,即左连接建右表索引。

alter table phone add index idx_phone_card(card)
alter table book add index id_book_card(card)

MySQL高级之索引优化分析_第27张图片
注:
join语句的优化,

  1. 尽可能减少join语句中的NestedLoop的循环总次数(join过多或join嵌套)。永远用小结果集驱动大结果集。(比如书籍类型表用于驱动书籍表)
  2. 优先优化NestedLoop的内层循环。
  3. 保证join语句中被驱动表上join条件字段已经被索引。
  4. 当无法保证被驱动表上join条件字段被索引且内存资源充足前提下,应调高JoinBuffer

B.索引失效(应该避免)

key = null,表示要么没建索引,要么索引失效。
1)全值匹配我最爱
全值指的是复合索引里的全值,匹配说的是在query语句中顺序匹配。
2)最佳左前缀法则
对于复合索引,要遵循最左前缀法则,意思是查询从索引的最左列开始并且不跳过中间的索引字段。一般跳过,则前面字段索引不失效,但是后面的索引字段失效了。
3)不在索引列上做任何操作(计算、函数、(自动或手动)类型转换),会导致索引失效而转向全表扫描。
MySQL高级之索引优化分析_第28张图片

4)存储引擎不能使用索引中范围条件右边的列。
在这里插入图片描述

5)尽量使用覆盖索引(只访问索引的查询(索引列和查询列一致),extra将出现using index,直接从index中拿),减少select *。
MySQL高级之索引优化分析_第29张图片
MySQL高级之索引优化分析_第30张图片

6)MySQL在使用不等于的时候无法使用索引会导致全表扫描
在这里插入图片描述
7)is null 、is not null 也无法使用索引
MySQL高级之索引优化分析_第31张图片
8)like以通配符开头,索引会失效变成全表扫描。
MySQL高级之索引优化分析_第32张图片
在这里插入图片描述
注:其实就是前面的%与最左前缀没了,导致所有失效。
如何解决%content%匹配?
create index idx_user_nameAge on user(name,age),建立复合索引,通过访问索引里的字段,从而将type=all升级为type=index

MySQL高级之索引优化分析_第33张图片
注:select列表中第一个加个id也许,毕竟id是主键,也为index。
9)字符串不加单引号索引失效
MySQL高级之索引优化分析_第34张图片
MySQL高级之索引优化分析_第35张图片

注:MySQL底层做了一个自动的隐式转换,int 到 string,像这种类型转换,就会索引失效。(一旦变成全表扫描,就非常糟糕。)

10)少用or,用它来连接时会索引失效。
MySQL高级之索引优化分析_第36张图片
11)小总结
MySQL高级之索引优化分析_第37张图片
MySQL高级之索引优化分析_第38张图片
注:c2已经为常量,被optimizer优化了。
在这里插入图片描述
在这里插入图片描述
注:
定值、范围还是排序,一般order by是给个范围。
group by基本上都要先排序,分完组会产生临时表,然后供select选择。

C.一般性建议

1)对于单键索引,尽量选择针对当前query过滤性更好的索引。
2)在选择组合索引的时候,当前query中过滤性最好的字段在索引字段中,位置越靠左越好。
3)在选择组合索引的时候,尽量选择可以能够包含当前query中的where子句中更多字段的索引。
4)尽可能通过分析统计信息和调整query的写法来达到选择合适索引的目的。
MySQL高级之索引优化分析_第39张图片
注:最后的c=4被优化了,非常重要的小知识点,c都一样了,所以直接按b来排序,所以会用整个索引。
注:SQL配合index改写口诀,
全值匹配我最爱,最左前缀要遵守;
带头大哥不能死,中间兄弟不能断;
索引列上少计算,范围之后全失效;
like百分写最右,覆盖索引不写*;
不等空值还有or,索引失效要少用。

你可能感兴趣的:(MySQL必知必会,mysql,索引优化)