数据库索引,相信你们都不陌生吧。面试
索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息。做为辅助查询的工具,合理的设计索引能很大程度上减轻db的查询压力,db咱们都知道,是项目最核心也是最薄弱的地方,若是压力太大很容易产生故障,形成难以预计的影响。因此,无论是平常开发仍是面试,索引这一块知识体系都是必须掌握的。算法
固然,虽然说是必须掌握,但索引的知识点不少,不少初学者常常会遗漏,这也是我为何想写这篇知识点总结的缘由,既是给读者的分享,也是给本身一次全面的复习,但愿对大家有所帮助。数据库
好了,废话很少说,进入正题。数组
首先声明一下,本文索引的知识点所有是基于MySQL数据库
优势:数据结构
1.大大加快数据的查询速度函数
2.惟一索引能够保证数据库表每一行的惟一性工具
3.加速表链接时间性能
缺点: 搜索引擎
1.建立、维护索引要耗费时间,因此,索引数量不能过多。spa
2.索引是一种数据结构,会占据磁盘空间。
3.对表进行更新操做时,索引也要动态维护,下降了维护速度
索引的出现是为了提升查询效率,可是实现索引的方式却有不少种,因此这里也就引入了索引模型的概念。这里介绍三种经常使用于索引的数据结构,分别是哈希表、有序数组和搜索树。
哈希表,也称散列表,主要设计思想是经过一个哈希函数, 把关键码映射的位置去寻找存放值的地方 ,读取的时候也是直接经过关键码来找到位置并存进去,这种数据结构的平均查找复杂度为O(1)。
好比咱们维护一张身份证信息和用户姓名的表,须要根据身份证号查询姓名,哈希索引大概是这样的:
这种索引结构优势在于随机添加或删除单个元素的效率高,缺点在于哈希表中的元素并不必定按顺序排列,因此若是想作区间查询的话是很慢的,
假设我想查找图中身份证号在[ID_card_n1, ID_card_n3]这个区间的全部用户的话,就必须所有扫描一遍了。
因此,哈希表这种结构适用于只有等值查询的场景
有序数组索引在等值查询和区间查询场景中的效率都很高,仍是拿上面的图作例子,用有序数组实现的话是这样子的:
数组的元素按身份证号有序排列,要查询数据的时候,使用二分法就能够快速获得,时间复杂度为O(logN),并且,由于是有序排列,查询某个区间内的数据也是很是的快。
固然,有序数组的缺点也很明显,就跟ArrayList同样,虽然搜索快,但添加删除元素都有可能要移动后面全部的元素,这是数组的自然缺陷。因此,有序数组索引只适用于静态存储引擎,好比你要保存的是2017年某个城市的全部人口信息,这类不会再修改的数据。
说到搜索树,咱们最熟悉的应该就是二叉搜索树了,二叉搜索树的特色是每一个结点的左儿子小于父结点,父结点又小于右儿子,而且左右子树也分别为二叉搜索树,平均时间复杂度是O(log2(n))。
它既有链表的快速插入与删除操做的特色,又有数组快速查找的优点,同时,由于自己二叉搜索树是有序的,因此也支持范围查找
这么提及来,其实二叉搜索树来作索引好像也是个不错的选择,其实否则
首先咱们要明确的一点是,这棵树是存在于磁盘中,每次咱们都要从磁盘中读取出相应的结点,然而二叉搜索树的结点在文件中是随机存放的,因此可能读取一个结点就须要一个磁盘IO,偏偏二叉搜索树都会比较高,如一棵一百万个元素的平衡二叉树就有十几层高度了,也就是大部分状况下检索一次数据就须要十几回磁盘IO,这个代价过高了,因此通常二叉搜索树也不会被用来做索引。
为了让一个查询尽可能少地读磁盘,就必须让查询过程访问尽可能少的数据块,也就是说,尽量的让树的高度变低,也就是用多路搜索树,而InnoDB存储引擎使用的就是这种多路搜索树,也就是咱们常说的B+树。
InnoDB是MySQL中最经常使用的搜索引擎,它的索引底层结构用的就是B+树,全部的数据都是存储在B+树中的。每个索引在InnoDB中对应一颗B+树。
B+树的特色是:
这种结构有两个优势:
按照结构来分的话,数据库索引能够分为聚簇索引和非聚簇索引。
聚簇索引,也叫汇集索引,就是按照每张表的主键构造一颗B+树,同时叶子结点中存放的就是整张表的行记录数据,简单点说,就是咱们常说的主键索引。在聚簇索引之上建立的索引称之为辅助索引,辅助索引访问数据老是须要二次查找。
非聚簇索引,也叫非汇集索引,二级索引。这种索引是将数据与索引分开存储,索引结构的叶子结点指向了数据对应的位置。
InnoDB使用的是聚簇索引,将主键组织到一棵B+树中,而行数据就储存在叶子节点上,咱们先假设一张用户表,这张表包含了id,name,company几个字段,
用图片表示InnoDB的索引结构大概是这样:
从图中就能够看出,若是咱们使用"where id = 14"这样的条件查找主键,则按照B+树的检索算法便可查找到对应的叶结点,以后得到行数据。
若对Name列进行条件搜索,则须要两个步骤:第一步在辅助索引B+树中检索Name,到达其叶子节点获取对应的主键。第二步使用主键在主索引B+树种再执行一次B+树检索操做,最终到达叶子节点便可获取整行数据。(重点在于经过其余键须要创建辅助索引)
这是聚簇索引的结构,而非聚簇索引的表明是MyISM,这也是MySQL中常见的搜索引擎。
非聚簇索引的两棵B+树看上去没什么不一样,结点的结构彻底一致只是存储的内容不一样而已,主键索引B+树的节点存储了主键,辅助键索引B+树存储了辅助键。索引自己不存储数据,数据存储在独立的地方,这两颗B+树的叶子节点都使用一个地址指向真正的表数据。
看上去,好像非聚簇索引的效率要高于聚簇索引,由于不用查两次B+树,那为何最经常使用的InnoDB引擎还要用这种存储结构呢?它自己的优点在哪?
一、聚簇索引中,因为行数据和叶子结点存储在一块儿,同一页中会有多条行数据,访问同一数据页不一样行记录时,已经把页加载到了Buffer中,再次访问的时候,会在内存中完成访问,没必要访问磁盘。这样主键和行数据是一块儿被载入内存的,找到叶子节点就能够马上将行数据返回了,因此,若是按照主键Id来组织数据,得到数据更快。
二、辅助索引使用主键做为"指针"而不是使用地址值做为指针的好处是,减小了当出现行移动或者数据页分裂时辅助索引的维护工做,使用主键值看成指针会让辅助索引占用更多的空间,换来的好处是InnoDB在移动行时无须更新辅助索引中的这个"指针"。也就是说行的位置(实现中经过16K的Page来定位)会随着数据库里数据的修改而发生变化(前面的B+树节点分裂以及Page的分裂),使用聚簇索引就能够保证无论这个主键B+树的节点如何变化,辅助索引树都不受影响。
三、聚簇索引适合用在排序、范围查询,非聚簇索引不适合。
说到辅助索引,咱们还能够延伸出另外一种特别的索引,就是覆盖索引。
上面说了,聚簇索引中访问数据要通过二次查找,就是先找到辅助键的叶子结点,获得主键对应的结点后再用主键索引查询数据,这样仍是比较慢的,其实,若是咱们所需的字段第一次查找就能获取到的话,就不用再二次查找主键了,也就是不用“回表”。
就仍是上面那张表有三个字段id,name,company的表来讲,我给name加了索引,在查询数据的时候,我就这么写语句:
select name from user where name like '张%';
由于咱们的语句走了索引,而且返回的字段在叶子结点都存在,查询的时候就不会回表了,多好啊~~
因此,若是所需的字段恰好是索引列的话,尽可能用这种查询方式,不要用select *
这种语句。
前面说的索引分类是按照结构来分,若是按做用范围来分的话,索引还能够分为如下几种:
普通索引:这是最基本的索引类型,没惟一性之类的限制。
CREATE INDEX INDEX_NAME ON TABLE_NAME(PROPERTY_NAME)
惟一性索引:和普通索引基本相同,但全部的索引列只能出现一次,保持惟一性。
CREATE UNIQUE INDEX INDEX_NAME ON TABLE_NAME(PROPERTY_NAME)
主键:跟惟一索引同样,不能有重复的列,但本质上,主键不能算是索引,而是一种约束,必须指定为"PRIMARY KEY"。它跟惟一索引的区别在于:
全文索引:全文索引的索引类型为FULLTEXT,能够在VARCHAR或者TEXT类型的列上建立。在MySQL5.6之前的版本,只有 MyISAM 存储引擎支持全文索引,5.6及以后的版本,MyISAM 和 InnoDB 存储引擎均支持全文索引。
CREATE FULLTEXT INDEX INDEX_NAME ON TABLE_NAME(PROPERTY_NAME)
联合索引:联合索引其实不是一种索引分类,就是包含多个字段的普通索引,好比有个联合索引为index(a,b),查找的时候能够用 a and b
做为条件,
联合索引中,最左优先,以最左边的为起点任何连续的索引都能匹配上。同时遇到范围查询(>、<、between、like)就会中止匹配。
就像上面说的index(a,b)或者是a单独做为查询条件都会走索引,可是若是是单独用 b 作查询条件就不会走索引了
或者是若是创建(a,b,c,d)顺序的索引的话,用a = 1 and b = 2 and c > 3 and d = 4这样的语句搜索,d是用不到索引的,由于c字段是一个范围查询,它以后的字段会中止匹配。
一、索引列用函数或表达式,好比这种
select * from test where num + 1 = 5
MySQL没法解析这种方程,这彻底是用户的行为,应该把索引列当成独立的列,这样索引才会生效。
二、存在NULL值条件
select * from user where user_id is not null;
咱们在设计数据库表时,应该尽力避免NULL值出现,若是数据有为空的状况能够给一个默认值,好比数值型的能够给0、-1,字符类型的能够给空字符串。
三、用or表达式做为条件,有一个列没有索引,那么其它列的索引将不起做用
select * from user where user_id = 700 or user_name = "老薛";
像这种,若是user_id有加索引,而user_name没有的话,那么执行的时候user_id的索引也是失效的,这也是为何开发中尽可能少用or的缘由,除非是两个字段都加了索引。
四、列与列对比,某个表中,有两列(id和c_id)都建了单独索引,下面这种查询条件不会走索引
select * from test where id = c_id;
五、数据类型的转换。若是列类型是字符串,那必定要在条件中将数据使用引号引用起来,不然不使用索引
create index `idx_user_name` ON user(user_name) select * from user where user_name = 123;
像上面这种,虽然给user_name创建了索引,但查询的时候条件没有当成字符串,这样的话就不会走索引。
六、NOT条件
当查询条件为非时,索引定位就困难了,执行计划此时可能更倾向于全表扫描,这类的查询条件有:<>、NOT、in、not exists
select * from user where user_id<>500; select * from user where user_id in (1,2,3,4,5); select * from user where user_id not in (6,7,8,9,0); select * from user where user_id exists (select 1 from user_record where user_record.user_id = user.user_id);
七、like查询是以%开头
当使用模糊搜索时,尽可能采用后置的通配符,例如要查姓张的人,能够用user_name like ‘张%’
,这样走索引时,能够从前面开始匹配索引列,但若是是这样user_name like ‘%张’
,那么就会走全表扫描的方式
八、多列索引,遵循最左匹配原则,这个上面说了
前面说了,索引虽然能加快查询速度,但自己也会占用空间,因此,索引的建立并非越多越好,为了使索引能有效应用,咱们要把索引留给最有用的查询字段,通常来讲,应该在这些字段上建立索引:
一样,对于有些字段不该该建立索引,这些列包括
explain是MySQL的关键字,经过该关键字咱们能够查看搜索语句的性能。
这是查询表的数量,一共有三千多万行,这么多的数据,咱们搜索的时候确定要用到索引才行,至于索引是否会生效,咱们也能够经过该关键字来看下
看,搜索的条数瞬间降到了16条,走的索引是 index_user_id
,证实咱们的索引是生效的。
关于explain的几个重要参数,咱们有必要了解一些:
id:查询的序列号
select_type:查询的类型,主要是区别普通查询和联合查询、子查询之类的复杂查询。
type:
type显示的是访问类型,是较为重要的一个指标,结果值从好到坏依次是:
system > const > eq_ref > ref >fulltext > ref_or_null > index_merge > unique_subquery >index_subquery > range > index > ALL
System效率最高,ALL的话已是全表扫描了,通常来讲,查询至少要达到range级别。
key:
显示MySQL实际决定使用的键。若是没有索引被选择,键是NULL。
key=primary的话,表示使用了主键; key=null表示没用到索引。
possible_keys:
指出MySQL能使用哪一个索引在该表中找到行。若是是空的,没有相关的索引。这时要检查语句中是否是有什么状况致使索引失效。
rows:
表示执行计划中估计扫描的行数,是个估计值。
Extra:
好了,索引的知识点就介绍到这了,最后总结一下索引的注意事项吧。
一、索引要根据表数据的使用状况来建立,不能建立太多,通常一张表不建议超过6个索引字段
二、好刀要用在刀刃上,常常用于查询,没多少重复数据,搜索行数不超过表数据量4%的字段用索引的效果比较好
三、建立联合索引要注意最左匹配原则,切记,最左边的字段是必传字段,这点我他妈就吃过大亏
四、查询语句要用explain执行计划来查看性能。
参考:
https://www.jianshu.com/p/fa8...
MySQL实战45讲
虽然都是基础知识,但也花了我一天的时间来整理了,洋洋洒洒五千多字,也算是一篇干货了,各位看官以为有所收获的话,还望能给鄙人来个转发或点赞之类的,不求四连,能双连或者是一连我都很满意了,大家的举手之劳就是我不断创做的动力!
做者:鄙人薛某,一个不拘于技术的互联网人,欢迎关注个人公众号,每周不按期更新干货文章,这里不只有技术,还有吹水~~~