Mysql ==》 索引原理与慢查询优化

一:介绍

为何要有索引?

回答:

一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,

在生产环境中,我们遇到最多的,也就是最容易出问题的,还是一些负责的查询操作,

因此对查询语句的优化显然是重中之重。说起加速查询,就不得不提到索引了。

什么是索引:

回答:

这里的索引,形象的可以理解为一本数中,里面的目录就索引。我们可以通过索引,快速查询到我们需要的数据。

专业说法:

索引在MySQL中也叫做“键”,是存储引擎用于快速找到记录的一种数据结构。索引对于良好的性能
非常关键,尤其是当表中的数据量越来越大时,索引对于性能的影响愈发重要。
索引优化应该是对查询性能优化最有效的手段了。索引能够轻易将查询性能提高好几个数量级。
索引相当于字典的音序表,如果要查某个字,如果不使用音序表,则需要从几百页中逐页去查。

二:索引的原理

索引的原理:

1.索引的目的在于提高查询效率。

与我们查阅图书所用的目录是一个道理:先定位到章,然后定位到该章下的一个小节,然后找到页数。

相似的例子还有:查字典,查火车车次,飞机航班等

本质都是:通过不断地缩小想要获取数据的范围来筛选出最终想要的结果,同时把随机的事件变成顺序的事件,

也就是说,有了这种索引机制,我们可以总是用同一种查找方式来锁定数据。

数据库也是一样,但显然要复杂的多,因为不仅面临着等值查询,还有范围查询(>、<、between、in)、模糊查询(like)、并集查询(or)等等。

数据库应该选择怎么样的方式来应对所有的问题呢?

我们回想字典的例子,能不能把数据分成段,然后分段查询呢?

最简单的如果1000条数据,1到100分成第一段,101到200分成第二段,201到300分成第三段......这样查第250条数据,只要找第三段就可以了,一下子去除了90%的无效数据。

但如果是1千万的记录呢,分成几段比较好?

稍有算法基础的同学会想到搜索树,其平均复杂度是lgN,具有不错的查询性能。

但这里我们忽略了一个关键的问题,复杂度模型是基于每次相同的操作成本来考虑的。

而数据库实现比较复杂,一方面数据是保存在磁盘上的,另外一方面为了提高性能,

每次又可以把部分数据读入内存来计算,因为我们知道访问磁盘的成本大概是访问内存的十万倍左右,

所以简单的搜索树难以满足复杂的应用场景。

三:索引的数据结构

以上是: b+树性质

1.索引字段要尽量的小

2.索引的最左匹配特性

三:mysql 索引管理

1.功能

1.索引的功能就是加速查找

2.mysql中的primary key,unique, 联合唯一也都是索引

2.mysql的索引分类

1.普通索引:

  index: 加速查找

2.唯一索引:

  主键索引  primary key : 加速查找+约束(不为空、不能重复)

  唯一索引 unique : 加速查找+约束 (不能重复)

3.联合索引:

  primary key(id,name)  -----联合主键索引

  unique(id,name)          -----联合唯一索引

  index(id,name)             -----联合普通索引

各个索引的运用场景:

举个例子来说,比如你在为某商场做一个会员卡的系统。

这个系统有一个会员表
有下列字段:
会员编号 INT
会员姓名 VARCHAR(10)
会员身份证号码 VARCHAR(18)
会员电话 VARCHAR(10)
会员住址 VARCHAR(50)
会员备注信息 TEXT

那么这个 会员编号,作为主键,使用 PRIMARY
会员姓名 如果要建索引的话,那么就是普通的 INDEX
会员身份证号码 如果要建索引的话,那么可以选择 UNIQUE (唯一的,不允许重复)

#除此之外还有全文索引,即FULLTEXT
会员备注信息 , 如果需要建索引的话,可以选择全文搜索。
用于搜索很长一篇文章的时候,效果最好。
用在比较短的文本,如果就一两行字的,普通的 INDEX 也可以。
但其实对于全文搜索,我们并不会使用MySQL自带的该索引,而是会选择第三方软件如Sphinx,专门来做全文搜索。

#其他的如空间索引SPATIAL,了解即可,几乎不用

3.索引的两大类型 hash 与 btree

#我们可以在创建上述索引的时候,为其指定索引类型,分两类
hash类型的索引:查询单条快,范围查询慢
btree类型的索引:b+树,层数越多,数据量指数级增长(我们就用它,因为innodb默认支持它)

#不同的存储引擎支持的索引类型也不一样
InnoDB 支持事务,支持行级别锁定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
MyISAM 不支持事务,支持表级别锁定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
Memory 不支持事务,支持表级别锁定,支持 B-tree、Hash 等索引,不支持 Full-text 索引;
NDB 支持事务,支持行级别锁定,支持 Hash 索引,不支持 B-tree、Full-text 等索引;
Archive 不支持事务,支持表级别锁定,不支持 B-tree、Hash、Full-text 等索引;

4.创建/删除索引的语法

方法一:创建表时

create table 表名 ( 
    字段1 数据类型 [完整性约束条件...],
    字段2 数据类型 [完整性约束条件...],
    [unique | fulltext | spatial ] index | key
    [索引名]  (字段名[(长度)] [asc | desc])
    );


方法二:create 在已存在的表上创建索引

create  [unique | fulltext | spatial ] index 索引名
    on 表名 (字段名[(长度)] [asc | desc]);

方法三:alter table 在已存在的表上创建索引

alter table 表名 add  [unique | fulltest |spatial ] index
    索引名 (字段名[(长度)]  [asc |desc] );


删除索引: drop  index  索引名 on 表名字;

四:测试索引

1.准备

#1. 准备表
create table s1(
id int,
name varchar(20),
gender char(6),
email varchar(50)
);

#2. 创建存储过程,实现批量插入记录
delimiter $$ #声明存储过程的结束符号为$$
create procedure auto_insert1()
BEGIN
    declare i int default 1;
    while(i<3000000)do
        insert into s1 values(i,concat('egon',i),'male',concat('egon',i,'@oldboy'));
        set i=i+1;
    end while;
END$$ #$$结束
delimiter ; #重新声明分号为结束符号

#3. 查看存储过程
show create procedure auto_insert1G 

#4. 调用存储过程
call auto_insert1();

2.在没有索引的前提下测试查询速度

3.加上索引之后

五:正确使用索引

 1.并不是索引建立了就会提升速度的,索引也要依照各种情况而定。如下索引就未命中

2.覆盖索引 与 索引合并(两个字段单独建立索引)

#覆盖索引:
    - 在索引文件中直接获取数据
    http://blog.itpub.net/22664653/viewspace-774667/

#分析
select * from s1 where id=123;
该sql命中了索引,但未覆盖索引。
利用id=123到索引的数据结构中定位到该id在硬盘中的位置,或者说再数据表中的位置。
但是我们select的字段为*,除了id以外还需要其他字段,这就意味着,我们通过索引结构取到id还不够,还需要利用该id再去找到该id所在行的其他字段值,这是需要时间的,很明显,如果我们只select id,就减去了这份苦恼,如下
select id from s1 where id=123;
这条就是覆盖索引了,命中索引,且从索引的数据结构直接就取到了id在硬盘的地址,速度很快
#索引合并:把多个单列索引合并使用

#分析:
组合索引能做到的事情,我们都可以用索引合并去解决,比如
create index ne on s1(name,email);#组合索引
我们完全可以单独为name和email创建索引

组合索引可以命中:
select * from s1 where name='egon' ;
select * from s1 where name='egon' and email='adf';

索引合并可以命中:
select * from s1 where name='egon' ;
select * from s1 where email='adf';
select * from s1 where name='egon' and email='adf';

乍一看好像索引合并更好了:可以命中更多的情况,但其实要分情况去看,如果是name='egon' and email='adf',那么组合索引的效率要高于索引合并,如果是单条件查,那么还是用索引合并比较合理

  

原文地址:https://www.cnblogs.com/zhongbokun/p/7512043.html