数据库索引深入理解
本文着重解决以下问题:
使用索引为什么可以加快数据库的检索速度啊?
为什么说索引会降低插入、删除、修改等维护任务的速度?
索引的最左匹配原则指的是什么?
Hash索引和B+树索引有什么区别?主流的使用哪一个比较多?InnoDB存储都支持吗?
聚集索引和非聚集索引有什么区别?
MySQL的基本储存结构是页
用户插入记录 记录可以一直插入直到占满了整个free space.此外 每个数据页可以组成一个双链表 每个数据页的记录又可以组成一个单向链表。每个数据页都会为储存在其中的记录生成一个页目录,通过主键查找可以通过二分法,而非主键的话只能遍历。因此 当我们写:select * from user where username = 'Java3y‘这样没有进行任何优化的sql语句,默认会这样做:
- 定位到记录所在的页 这就需要遍历双向链表,找到所在的页
- 从所在的页内中查找相应的记录 由于不是根据主键查询,只能遍历所在页的单链表了
而索引做了什么可以加快检索速度呢?
他其实是将无序的数据变为相对有序。
但是索引的加入同时也会降低增删改查的速度:因为B+树是自平衡树,虽然有着稳定的查找效率 但是在需要改动时 要做大量维护。
除了B+索引之外 我们还有hash索引,即把键换位hash值 根据这个hash值来判断在内存或硬盘中的位置,而且比B+树要好得多
但是其缺点非常明显:没法排序 不支持最左匹配原则,有大量重复的键 不支持范围查询等等
那么InnoDB支持hash索引吗?
对于哈希索引,InnoDB是自适应哈希索引的(hash索引的创建由InnoDB存储引擎引擎自动优化创建,我们干预不了)
聚集索引和非聚集索引的区别:
简单概括 就是:聚集索引是以主键创建的索引 非聚集索引是以非主键创建的索引(?)
深入一点 就是:聚集索引在叶子节点存储的是表中的数据 非聚集索引在叶子节点存储的是主键和索引列
使用非聚集索引查询出数据时,拿到叶子上的主键再去查到想要查找的数据。(拿到主键再查找这个过程叫做回表) 就像fk一样
什么是索引最左匹配原则?
最左匹配原则:(即从左边开始匹配)
索引可以简单如一个列(a),也可以复杂如多个列(a, b, c, d),即联合索引。
如果是联合索引,那么key也由多个列组成,同时,索引只能用于查找key是否存在(相等),遇到范围查询(>、<、between、like左匹配)等就不能进一步匹配了,后续退化为线性查找。
因此,列的排列顺序决定了可命中索引的列数。
比如说:如有索引(a, b, c, d),查询条件a = 1 and b = 2 and c > 3 and d = 4,则会在每个节点依次命中a、b,无法命中d。(很简单:索引命中只能是相等的情况,不能是范围匹配)
但是我们不需要考虑列的排列顺序 因为MySQL会自动调优:如有索引(a, b, c, d),查询条件c > 3 and b = 2 and a = 1 and d < 4与a = 1 and c > 3 and b = 2 and d < 4等顺序都是可以的,MySQL会自动优化为a = 1 and b = 2 and c > 3 and d < 4,依次命中a、b。
索引听起来和主键很像,那么究竟有什么区别呢?
总结的来说 索引是一个比主键大得多的概念。
两者的区别:
1:主键是为了标识数据库记录唯一性,不允许记录重复,且键值不能为空,主键也是一个特殊索引.
2:数据表中只允许有一个主键,但是可以有多个索引.
3.使用主键会数据库会自动创建主索引,也可以在非主键上创建索引,方便查询效率.
4:索引可以提高查询速度,它就相当于字典的目录,可以通过它很快查询到想要的结果,而不需要进行全表扫描.
5:主键索引外索引的值可以为空.
6:主键也可以由多个字段组成,组成复合主键,同时主键肯定也是唯一索引.
7:唯一索引则表示该索引值唯一,可以由一个或几个字段组成,一个表可以有多个唯一索引.
对索引的进一步说明:
索引在数据库中是一个非常重要的知识点!上面谈的其实就是索引最基本的东西,要创建出好的索引要顾及到很多的方面:
1,**最左前缀匹配原则。**这是非常重要、非常重要、非常重要(重要的事情说三遍)的原则,MySQL会一直向右匹配直到遇到范围查询(>,<,BETWEEN,LIKE)就停止匹配。
3,尽量选择区分度高的列作为索引,区分度的公式是 COUNT(DISTINCT col) / COUNT(*)。表示字段不重复的比率,比率越大我们扫描的记录数就越少。
4,索引列不能参与计算,尽量保持列“干净”。比如,FROM_UNIXTIME(create_time) = ‘2016-06-06’ 就不能使用索引,原因很简单,B+树中存储的都是数据表中的字段值,但是进行检索时,需要把所有元素都应用函数才能比较,显然这样的代价太大。所以语句要写成 : create_time = UNIX_TIMESTAMP(‘2016-06-06’)。
5,尽可能的扩展索引,不要新建立索引。比如表中已经有了a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可。
6,单个多列组合索引和多个单列索引的检索查询效果不同,因为在执行SQL时,MySQL只能使用一个索引,会从多个单列索引中选择一个限制最为严格的索引。

浙公网安备 33010602011771号