一:介绍
为何要有索引?
回答:
一般的应用系统,读写比例在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',那么组合索引的效率要高于索引合并,如果是单条件查,那么还是用索引合并比较合理