MySQL优化-索引

Posted 小周祖传代码

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL优化-索引相关的知识,希望对你有一定的参考价值。

索引

1. 概述

​ 索引的作用是帮助mysql高效的获取数据中的数据结构(有序),在数据之外,数据库系统还维护着满足特定的查找算法的数据结构,这些数据结构通过某种方式引用指向数据,这样就可以在这些数据结构之上实现高级的查找算法,这种数据结构就是索引。

​ 一般来说索引本身也是十分的大,不可能全部存储在内存中,因此索引往往会通过索引的文件形式存储在磁盘上,索引是数据库中用来提高性能的最常用的工具。

1.1 对比

​ 对于没有建立索引的数据表,每一次的查询的操作都是从上到下的进行遍历的操作,也就是说只有找到对应的数据,才遍历成功。

​ 建立索引的作用是对数据库表中的一列或者多列的值进行一种排序的一种结构(B树),使用索引能够快速的访问数据库表中的特定的信息。

2. 索引的优势和劣势

2.1 优势

  1. 类似于书籍的索引的操作,提高数据的检索的效率,降低数据的成本
  2. 通过索引列的对数据进行排序的操作,降低数据的排序的成本,降低CPU的性能的消耗

2.2 劣势

  1. 实际上索引也是一张表,该表保存了主键和索引的字段,并且指向了实体类的记录,所以索引列也是要占据空间的。
  2. 索引虽然能够提高了查询的效率,但是同时却也降低了更新表的速度,比如对于表进行增、删除、修改的操作。因为更新表的时候,Mysql不仅仅要保存数据,还要保存一下索引文件每一次更新提那家索引列的字段。都会调整因为更新之后所带来的键值对的变化的索引的信息。

3.索引的结构

索引 是在mysql的存储的引擎层实现的,而不是在服务器层实现的,所以每种存储引擎的索引都是不一定完全的相同,也不是所有的存储的引擎都是支持所有的索引类型的,Mysql目前提供了下面的4 中索引。

  • b tree : 最常见的索引的类型,使用的场景比较简单。
  • Hash ;只有Memory 引擎能够支持,使用的场景比较简单。
  • R tree 空间的索引: 空间的索引是MylSAM 引擎的一个特殊索引类型,主要用于地理空间的数据类型,通常使用的比较少,不做特别的说明。
  • Full-text 全文的索引: 全文的索引也是MylSAM 中的一个特殊的引用类型,主要用于全文的索引。

平时如果没有说的索引,都是指B+树(多路搜索树,并不一定是二叉)结构组织的索引。其中的聚集索引、前缀索引、唯一的索引都是默认使用B+树索引,统称为索引。

3.1 BTree结构

BTree 又叫做多路平衡搜索树,一颗m叉的BTree 特性如下:

  1. 树中的每个节点最多的包含m个孩子。
  2. 除了根节点和叶子节点之外,每个节点至少有ceil(m/2)个孩子
  3. 如果根节点不是叶子节点,则至少会有两个孩子
  4. 所有的叶子节点都是在同一层。
  5. 每一个非叶子节点由n个key与n+1 个指针组成,其中 ceil(m/2) - 1 <= n < = m-1

3.2 B+Tree结构

B+ 树 是B Tree的变种,B+树和B树的区别:

  1. n叉B+树最多含N个key,而BTree最多含有 n-1 个key。
  2. B+树的叶子节点保存所有的key信息,依照key的大小进行顺序的排序。
  3. 所有的非叶子节点都可以看做是key的索引的部分。

4. 索引的分类

  1. 单值索引:既一个索引仅仅只能包含单个列,一个表可以有多个单列索引。
  2. 唯一索引:索引列的值必须唯一,但允许有空值。
  3. 复合索引:即一个索引包含多个列。
  4. 主键索引:主键会自动的帮助我们创建一个索引叫做主键索引。

5.索引的语法

5.1 创建索引

在创建表的时候建立索引操作,注意主键ID数据库引擎会给其索引

5.1.1 普通的索引

-- 在book表中的year_publication字段上建立普通索引
CREATE TABLE book
(
  bookid              INT NOT NULL,
  bookname            VARCHAR(255) NOT NULL,
  authors             VARCHAR(255) NOT NULL,
  info                VARCHAR(255) NULL,
  comment             VARCHAR(255) NULL,
  year_publication    YEAR NOT NULL,
  -- 表示的是普通的索引
  INDEX(year_publication)
);

-- 使用EXPLAIN语句查看索引是否正在使用
explain select * from book where year_publication=1990;

5.1.2 唯一索引

-- 创建一个表t1,在表中的id字段上使用UNIQUE关键字创建唯一索引
CREATE TABLE t1
(
  id   INT NOT NULL,
  name CHAR(30) NOT NULL,
  UNIQUE INDEX UniqIdx(id)
);

5.1.3 单列索引

-- 创建一个表t2,在表中的name字段上使用创建单列索引
CREATE TABLE t2
(
  id   INT NOT NULL,
  name CHAR(50) NULL,
  INDEX SingleIdx(name(20))
);

5.1.4 组合索引

-- 创建表t3,在表中的id,name和info字段上建立组合索引
CREATE TABLE t3
(
  id    INT NOT NULL,
  name  CHAR(30) NOT NULL,
  age   INT NOT NULL,
  info  VARCHAR(255),
  INDEX MultiIdx(id, name, info(100))
);

5.1.5 全文索引

-- 创建表t4,在表中的info字段上建立全文索引
CREATE TABLE t4
(
  id    INT NOT NULL,
  name  CHAR(30) NOT NULL,
  age   INT NOT NULL,
  info  VARCHAR(255),
  FULLTEXT INDEX FullTxtIdx(info)
) ENGINE=MyISAM;

5.1.6 空间索引

-- 创建表t5,在空间类型为GEOMETRY的字段上创建空间索引
CREATE TABLE t5 ( 
	g GEOMETRY NOT NULL, 
	SPATIAL INDEX spatIdx ( g ) 
) ENGINE = MyISAM;

5.2 查看索引

show index from table_name;
show keys from table_name;

5.3 删除索引

-- 删除book表中的名称为UniqidIdx的唯一索引
ALTER TABLE book DROP INDEX UniqidIdx;

-- 删除book表中名称为BkAuAndInfoIdx的组合索引
DROP INDEX BkAuAndInfoIdx ON book;

5.4 ALTER命令

-- 创建普通的索引
ALTER TABLE table_name ADD INDEX index_name (Att_name_1);


6.索引的设计原则

​ 索引的设计可以遵循一些已经存在的原则,创建索引的时候请尽量考虑符合的这些的原则,便于提升索引的使用的效率,更高效的使用索引。

  1. 对于查询的频次较高,但是数据量比较大的表建立索引。
  2. 索引字段的选择,最佳候选应当从where子句中的条件中提取出来,如果where子句中的组合比较作,那么应当挑选最常使用的,过滤效果最好的列的组合。
  3. 使用唯一索引,区分度越高,使用的索引的效率越高。
  4. 索引可以有效的提升查询数据的效率,但是索引的数量不是多多益善,索引越多维护索引的代价自然就很大。对于插入、更新、删除等DML操作比较频繁的表来说,索引过多,会引入相当高的维护的代价,降低DML操作的效率,增加相对应的操作的时间。另外索引过多的话,MySQL也会犯选择困难的病症,虽然最终仍然会找到一个可用的索引,但是无疑会提高了选择的代价。
  5. 使用短索引,索引创建之后也是使用硬盘来进行存储的,因此提升索引访问IO效率,也可以提升总体的访问的效率,加入构成索引的总长度比较短,那么在给定大小的存储块内可以存储更多的索引的值,相应的可以有效的提升MySQL访问索引的IO效率。
  6. 利用最左前缀,N个列组合组成的组合索引,那么相当于是创建了N个索引,如果查询时where子句中使用了组成索引的前几个字段,那么这条查询SQL可以利用组合索引来提升查询的效率。

7. 索引的使用

​ 索引是数据库优化最常用也是最重要的手段之一,通过索引通常能够帮助用户解决大多数的MySQL的性能的问题。索引的应用的场景是在多条的数据中才能够实现操作。

​ 数据库的优化的操作能够通过索引来实现。

7.1 验证索引提升查询效率

首先准备的表结构是200多万条数据。

  • 根据ID进行查找操作
select *
from salaries
where emp_no = 10009;
-- 此时存在索引

  • 查询索引
show index from salaries;

  • 查询没有索引的数据的信息
select *
from salaries
where salary = 60117;

  • 给没有索引的信息添加上索引
-- 添加索引操作
create index idx_employee_salary on salaries(salary);

-- 创建索引之后的查询操作,查询速度快速上升
select *
from salaries
where salary = 66074;

总结:索引是数据库优化的重要的手段之一,能够优化查询的效率

7.2 索引的使用

在索引的使用的验证中,我们能够通过explain来进行判断操作,判断时候经历过索引的操作,其中的type中的ALL表示的是全表的扫描操作,Ref表示的是走过索引类型,其中的key_len表示的是索引的长度,也就是索引执行的长度。

在使用explain下,会出现的表单中含有的数据是extra中包含的元素包括

  1. using index : 使用覆盖索引的时候就会出现
  2. using where: 在查找使用索引的情况下,需要回表查询所需要的数据。
  3. using index condition :查找使用了索引,但是需要回表查询数据。
  4. using index;using where :查找使用了索引,但是需要的数据都在索引列中能够找到,所以不需要回表查询数据。

比如说:4 中通过索引查找到了指定的信息,但是需要通过回表的操作,回到数据表中查询指定的条件的数据。然后进行输出的操作。

7.1.1 避免索引失效

  1. 全值匹配,对于索引中所有列都是有指定具体值。
  2. 最左前缀法则:
  3. 范围查询,右边的列,不能够使用索引
  4. 在某一列上使用了运算操作,索引将失效
  5. 字符串不加单引号,造成索引失效
  6. 尽量使用覆盖索引,避免使用select*
  7. 使用or分割的条件
  8. 通过%开头的like模糊查找,索引失效
  9. 如果mysql评估使用索引比全表扫描更慢,则不使用索引。
  10. is NULL 和 NOT NULL有时候会出现索引失效。
1. 全值匹配

对于索引中的所有的列都能够指定具体的值,这个时候,索引生效,执行的效率较高。

2. 最左前缀法则

如果索引了多列,需要遵循最左的前缀法则。指的是查询从最左前列开始,并且不会跳过索引中间的列。否则就不会走索引的操作。

3. 范围查询

范围查询右边的列,不能够使用索引。根据前面的两个字段name,status,查询是走索引的,但是最后的一个条件address没有用到索引

4 .运算操作

如果在某个列上进行运算操作,索引将失效

5. 字符操作

字符串不加单引号,造成索引失败。

6. 覆盖索引

​ 尽量使用覆盖索引,能够有效的避免select*,如果使用的是select* * 的操作,那么就会出现的操作是using index condition 的操作,查找中使用了索引,但是还是需要进行回表查询数据的操作。如果使用的是select name ,status 等条件,则Extra下面会出现 using where;using index,表示的是查找中使用了索引,但是需要的数据都在索引列总找到,所以不需要进行回表查询的操作。

7. or分割

使用or分割的条件,如果or前面的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到。示例:name 字段是索引列,而 create_time 不是索引列,中间是通过or连接的,是不走索引的。如果将or换成and,那么也将会走索引的操作,扫描的是一行的记录

8. 模糊查找

​ 通过% 开头的like模糊查找,索引失效,如果仅仅是尾部模糊匹配,索引不会失效。如果此时能够能够避免覆盖索引的操作,其中的筛选的条件是索引固定的内容,那么就会通过索引进行查询,如果select 条件中没有索引固定的内容,那么就会出现不会走索引的情况。总结:对于模糊查找不能够通过索引的方式显示,那么就通过使用覆盖索引的方式实现操作。

9. 放弃索引

如果MySQL评估使用索引比全表更慢,即不使用索引。也就是说数据量比较大,某一条数据占得比重比较大,所以这个时候就不会使用索引的操作方式,而是采用全表的扫描的形式进行实现。

10 . is NUll ,is Not NULL

is NUll ,is Not NULL有时会出现索引失效的情况存在。

11. in not in

in : 表示的是使用索引

not in : 表示的是索引失效,即总结得出,在编写SQL语句的时候尽量多使用in 而非not in

12. 单列索引、复合索引

尽量使用复合索引操作,而少使用单列索引的操作。

创建复合索引的操作

create index idx_name_sta_address on tb_Seller(name,status,address);

-- 相当于创建三个索引
name 
name + status
name + status + address

-- 数据库会选择一个最优的索引来使用后,并不会使用全部的索引
-- 对于辨识度最高的,将作为数据库的使用的优先选择的条件。

7.3 查看索引使用情况


-- 表示的是当前会话的索引的使用情况
show status like 'Handler_read%';

-- 表示的是全局的索引的使用情况
show global status like 'Handler_read%'

mysql---索引优化

参考技术A 索引就是为特定的mysql字段进行一些特定的算法排序,比如二叉树的算法和哈希算法,哈希算法是通过建立特征值,然后根据特征值来快速查找。

1.普通索引:(index)最基本的索引,没有任何限制  目的:加快数据的查询速度

2.唯一索引:(unique)  与"普通索引"类似,不同的就是:索引列的值必须唯一,但允许有空值。

3.主键索引(primary key) 它 是一种特殊的唯一索引,不允许有空值。

4.复合索引:index(a,b,c)  为了更多的提高mysql效率可建立组合索引,遵循”最左前缀“原则。

5.全文索引:fulltext  仅可用于 MyISAM 表,针对较大的数据,生成全文索引很耗时耗空间。

第一类是myisam存储引擎使用的叫做b-tree结构,

第二类是innodb存储引擎使用的叫做聚簇结构(也是一种 b-tree)。 如下图:

注意:

1.myisam不需要回行处理 

2.innodb不需要回行处理,直接可以获取数据,因为innodb的储存引擎是包含了数据和索引文件的,其主键索引包含了数据,(唯一索引及普通索是没有直接包含数据的)

1、索引列不能参与计算

​ 有索引列参与计算的查询条件对索引不友好(甚至无法使用索引),如from_unixtime(create_time) = '2014-05-29'。

​ 原因很简单,如何在节点中查找到对应key?如果线性扫描,则每次都需要重新计算,成本太高;如果二分查找,则需要针对from_unixtime方法确定大小关系。

因此,索引列不能参与计算。上述from_unixtime(create_time) = '2014-05-29'语句应该写成create_time = unix_timestamp('2014-05-29')。

2、最左前缀匹配

​ 如有索引(a, b, c, d),查询条件a = 1 and b = 2 and c > 3 and d = 4,则会在每个节点依次命中a、b、c,无法命中d。也就是最左前缀匹配原则。

3、冗余和重复索引

​ ​ 冗余索引是指在相同的列上按照相同的顺序创建的相同类型的索引,应当尽量避免这种索引,发现后立即删除。比如有一个索引(A,B),再创建索引(A)就是冗余索引。冗余索引经常发生在为表添加新索引时,比如有人新建了索引(A,B),但这个索引不是扩展已有的索引(A)

4、避免多个范围条件

        select user.* from user where login_time > '2017-04-01' and age between 18 and 30;

​ 比如想查询某个时间段内登录过的用户:它有两个范围条件,login_time列和age列,MySQL可以使用login_time列的索引或者age列的索引,但无法同时使用它们 .

5、覆盖索引 (能扩展就不新建)

​ 如果一个索引包含或者说覆盖所有需要查询的字段的值,那么就没有必要再回表查询,这就称为覆盖索引。覆盖索引是非常有用的工具,可以极大的提高性能,因为查询只需要扫描索引会带来许多好处:

1.索引条目远小于数据行大小,如果只读取索引,极大减少数据访问量2.索引是有按照列值顺序存储的,对于I/O密集型的范围查询要比随机从磁盘读取每一行数据的IO要少的多

6、选择区分度高的列作索引

如,用性别作索引,那么索引仅能将1000w行数据划分为两部分(如500w男,500w女),索引几乎无效。

区分度的公式是count(distinct ) / count(*),表示字段不重复的比例,比例越大区分度越好。唯一键的区分度是1,而一些状态、性别字段可能在大数据面前的区分度趋近于0。

7、删除长期未使用的索引

场景一(覆盖索引 5)

索引应该建在选择性高的字段上(键值唯一的记录数/总记录条数),选择性越高索引的效果越好、价值越大,唯一索引的选择性最高;

组合索引中字段的顺序,选择性越高的字段排在最前面;

where条件中包含两个选择性高的字段时,可以考虑分别创建索引,引擎会同时使用两个索引(在OR条件下,应该说必须分开建索引);

不要重复创建彼此有包含关系的索引,如index1(a,b,c) 、index2(a,b)、index3(a);

组合索引的字段不要过多,如果超过4个字段,一般需要考虑拆分成多个单列索引或更为简单的组合索引;

不要滥用索引。因为过多的索引不仅仅会增加物理存储的开销,对于插入、删除、更新操作也会增加处理上的开销,而且会增加优化器在选择索引时的计算代价。

因此太多的索引与不充分、不正确的索引对性能都是毫无益处的。一言以蔽之,索引的建立必须慎重,对每个索引的必要性都应该经过仔细分析,要有建立的依据。

以上是关于MySQL优化-索引的主要内容,如果未能解决你的问题,请参考以下文章

MySQL索引原理及SQL优化

MySQL 索引优化器选择索引的规则是啥?

mysql--索引优化

mysql---索引优化

mysql对于大量数据,怎么进行优化

MySQL索引优化