正文:sql
1、先说说什么是索引? 索引(index)翻译为一个目录,用于快速定位咱们想要找的数据的位置。例如:咱们把一个数据库比做一本书,而索引(index)就是书中的目录,此刻要找到书的某个感兴趣的内容,咱们通常是不会整本书翻完再去确认该内容在哪里,而是经过书的目录,定位到该内容章节所在页数,最后直接翻到该页面数据库
咱们来看看在数据库中的索引: 全表扫描 VS 索引扫描 以字典为例,全表扫描就是若是咱们查找某个字时,那么通读一遍新华字典,而后找到咱们想要找到的字 而跟全表扫描相对应的就是索引查找,索引查找就是在表的索引部分找到咱们想要找的数据具体位置,而后会到表里面将咱们想要找的数据所有查出服务器
实例:在一张学生表找到一个名字叫Dev的学生函数
左边全表扫描:须要从第一行开始一行行的扫描,直到找到100008行Dev这个学生的信息为止,将这个数据返回回来,但有可能该表中还有同名的学生,所以扫描并无结束,一般全表扫描要找到一个数据,是须要将整张表的数据遍历一遍,而后才能肯定是否将全部数据返回工具
右边索引扫描:索引查找是根据首字母排序找到D开头的Dev,若是首字母相同,那么再根据第二个字母排序找到,以此类推,咱们找到ID为100008,而后回表查出ID为100008的数据性能
结论:所以索引(对应InnoDB)的索引值对应的是主键IDfetch
2、如何找到索引对应的值 InnoDB引擎主要根据 (1)B+tree (2)二分查找法ui
B+tree: B+树拥有整棵树的根节点、支节点和页节点,上层会存储下层节点的管理范围,直到页节点的具体信息编码
二分查找法:根据B+树存储的各个节点的范围,进行比较,逐步缩小范围,最后定位到页节点中咱们想要的位置命令行
3、介绍下InnoDB表也是一张索引表
如上图InnoDB表是聚簇表,意思是InnoDB自己是一张大的索引组织表,也是一个根据主键排序的大索引的B+树结构,咱们在InnoDB里面另外创建本身想要索引的表的字段
聚簇索引就意味着InnoDB表自己,而咱们把这些根据其余字段排序的索引称为二级索引(secondery class)
4、在数据库中如何创建索引 在MySQL中主要创建两种类型的索引
1.单列索引
create index idx_name on tb_student(name); 索引名 表名 字段名 2.联合索引
create index idx_name_age on tb_student(name,age); #索引中先根据name排序,name相同的状况下根据age排序
5、索引维护 首先介绍下什么是索引维护?这是一个关乎性能的重要概念
若是索引所在字段发生了修改、删除、插入等操做,那么索引项就会发生变化,所以若是不能保证索引的有序,那么就不能索引的准确与效率,而索引的排序发生了变化的这个行为,咱们称为索引维护
在insert/delete/update操做时,为了维护索引的排序,数据库会自动的完成索引项的维护,索引的排序,这些行为对用户是透明的,感受不到的
在一个有索引的表中,建立它时,实际上还同时建立了索引排序的表,所以在DML中,插入等操做再也不是普通的插入,MySQL将它封装成了一个事务,连着索引项的排序表一块儿操做
所以,咱们应当严格控制表上的索引数量,不然容易影响数据库的性能
总结索引维护以下:
一、索引维护由数据库自动完成 二、插入/修改/删除每个索引行都变成一个内部封装的事务 三、索引越多,事务越大,代价越高 四、索引越多,对表的插入和索引字段的修改就越慢 所以能够看出索引并不是是越多越好,在工做中也要慎用,尤为对于写操做较为频繁的业务
6、如何正确的使用索引? 一、依据where查询条件创建索引
eg: select a,b from tb_test where c = ?; idx_c(c) ->正确
select a,b from tb_test where c = ? and b = ? idx_cd(c,d) ->正确 二、根据排序order by ,group by , distinct 字段添加索引
eg: select * from tb_test order by a; select a,count(*) from tb_test group by a; idx_a(a) ->正确
select * from tb_test order by a,b; idx_a_b(a,b) ->正确
select * from tb_test order where c = ? by a; idx_c_a(c,a) ->正确 7、到底哪些字段适合建立索引? 一、字段值的重复程度,如图:
身份证号码因为基本上不可能重复,所以选择性很是好,而人的名字重复性较低,选择性也不错, 性别选择性较差,重复度很是高
二、选择性不好的字段一般不适合建立索引,但也有例外
如:男女比例相仿的表中,性别不适合建立单列索引,若是走索引不如走全表扫描, 由于走索引的I/O开销更大
但若是男女比例极度不平衡,要查询的又是少数方,如:理工学校、IT公司等能够考虑使用索引 三、联合索引中选择性好的字段应该排在前面
select * from tab_a where gender=? and name=? idx_name_gender(name,gender) ->正确 四、联合索引能够为单列、复列查询提供帮助
idx_smp(a,b,c) where a=?; ->正确 where a=? and b=?; ->正确 where a=? and c=?; ->正确 (注:须要MySQL5.6版本以上;在5.5及之前版本,能够对a字段进行索引扫描,但c字段不行) where a=? and b=? and c=? ->正确 五、合理建立联合索引,避免冗余
(a),(a,b),(a,b,c) ->不可取 (a,b,c) ->正确,能够覆盖前两个 8、再来看看如何在长字段上创建索引呢 首先,在较长的字段上创建索引是很是影响性能的,好比文章等超大varchar或者text字段,若是不是非建不可,通常不推荐,另外对InnoDB索引单字段(utf8)只能取前767bytes
那么如何处理长字段索引?
主要根据类型来分别处理: 一、Email类,能够创建前缀索引 mail_addr varchar(2048) idx_mailadd(mail_addr(39)) -> 正确 解析:因为email邮件类型字段,通常后缀都有较大可能相同,如.com .cn等等, 而前缀相同的可能性较低,且邮箱通常长度较短,所以能够创建前缀索引
二、住址类,分拆字段 home_addr varchar(2048) idx_homeadd(home_addr(30)) ->错误,极可能前半段是相同的省市区街道名
province_add varchar(1024), city_add varchar(1024), district_add `varchar(1024), lolcal_add varchar(1024) --创建联合索引或者单列索引 ->正确 9、对核心SQL索引作覆盖扫描 对于最核心的SQL,咱们能够考虑使用索引覆盖,什么是索引覆盖呢,下面是个例子
select name from tb_user where userid=? key idx_uid_name(userid,name) ->覆盖索引扫描 咱们查询用户名这种操做频率很是高,而索引里面又存储了字段的值,所以在咱们作查询时,name字段的值直接在索引中返回,而不须要回表;还有一个使用很是普遍的例子:用户登录,咱们能够将username password作覆盖索引,这样大大提升登录验证的速度
所以覆盖索引覆盖就是将你要查询的字段和条件字段一块儿创建联合索引,这样的好处是不须要回表获取name字段,IO最小,速度块
10、哪些状况没法使用索引? 一、索引列进行数据运算或者函数运算
eg: where id+1=10; ->错误,没法利用到索引 where id=(10-1) ->正确
where year(id) < 2016 ->错误,没法利用到索引 where col < '2016-01-01' ->正确
二、未含复合索引的前缀字段
idx_abc(a,b,c) where b=? and c=? ->错误,没法利用到索引 正确的创建索引方式(b,c) 三、前缀通配符"_" "%"等
like '%ttt%' ->错误,没法利用到索引 like "ttt%" ->正确 四、where条件使用NOT,<>,!= 一般也没法使用到索引
五、字段类型不匹配
字段类型并不绝对匹配时,可能会致使没法使用索引 a int(11) ,idx_a(a) where a = '123' ->错误,可能致使未知的错误,这个跟编码有关系 where a = 123 ->正确
11、利用索引作排序操做 以 idx_ab(a,b)索引为例 一、能使用上述索引进行排序的操做是: order by a; a = 3 order by b; order by a,b; order by a desc ,b desc; a > 5 order by a; 二、不能使用索引帮助排序的查询
order by b; #没有使用到联合索引的第一个字段
a > 5 order by b;
#一旦前缀操做是一个range而非=操做,那么就没法利用到索引, 这里 a>5没法利用索引,二联合索引的第一个字段未利用, 所以 order by b也没法利用索引查询
a in (1,3) order by b; #in里面的值没有创建索引,所以没法利用索引,a未用所以order by b也没法使用
order by a asc, b desc; #这里order by a esc是利用了索引,可是b desc未利用到,由于b要和a排序方式一致才可利用到索引
12、如何肯定一个查询有没有走索引,走了哪些索引? MySQL中自带命令行工具 explain 来查看一个sql语句是否了索引
使用方式:
explain select * from tb_test; 关注的项:
一、type : 查询access的方式,表的链接类型
index | 索引 full | 全表扫描 ref | 参照查询,也就是等值查询 range | 范围查询
二、key : 本次查询最终选择使用哪一个索引,NULL为未使用索引 三、key_len : 选择的索引使用的前缀长度或者整个长度 四、rows : 查询逻辑扫描过的记录行数 五、extra : 额外信息,主要是指fetch data的具体方式 总结:索引的本质仍是提高咱们查询数据库的速度,减小服务器I/O开销,提供更稳定快捷的服务