MySQL实战45讲Day04----索引

一、索引:

1、索引存在的意义:为了提高数据查询的效率,对于数据库的表而言,索引其实就是它的“目录”。

2、索引的常见模型:哈希表、有序数组和搜索树。

    1).哈希表是一种以键-值(key-value)存储数据的结构,我们只要输入待查找的值即key,就可以找到其对应的值即Value。哈希的思路很简单,把值放在数组里,用一个哈希函数把key换算成一个确定的位置,然后把value放在数组的这个位置。哈希冲突的处理办法:链表哈希表适用于只有等值查询的场景。(即:哈希表添加数据速度快,但查询的速度很慢)。

    2).有序数组在等值查询和范围查询场景中的性能都非常优秀有序数组索引只适用于静态存储引擎。查询时可以用二分法快速得到,这个时间复杂度是O(log(N))。(即:数组查询数据的速度很快,但更新数据的速度很慢)。

    3).二叉搜索树的特点是:每个节点的左儿子小于父节点,父节点又小于右儿子。查询时的时间复杂度是O(log(N))。为了维持O(log(N))的查询复杂度,需要保持这棵树是平衡二叉树。为了做这个保证,更新的时间复杂度也是O(log(N))。实际上大多数的数据库存储却并不使用二叉树。其原因是,索引不止存在内存中,还要写到磁盘上。在机械硬盘时代,从磁盘随机读一个数据块需要10 ms左右的寻址时间。也就是说,对于一个100万行的表,如果使用二叉树来存储,单独访问一个行可能需要20个10 ms的时间,非常慢。为了让一个查询尽量少地读磁盘,就必须让查询过程访问尽量少的数据块。那么,就不应该使用二叉树,而是要使用“N叉”树。这里,“N叉”树中的“N”取决于数据块的大小。多叉树就是每个节点有多个儿子,儿子之间的大小保证从左到右递增。

二、InnoDB 的索引模型:

1、在InnoDB中,表都是根据主键顺序以索引的形式存放的,这种存储方式的表称为索引组织表。InnoDB使用的是B+树索引模型,所以数据都是存储在B+树中的。每个索引在InnoDB里面对应一棵B+树。也就是说:每一张表其实就是多棵B+树,树结点的key值就是某一行的主键,value是该行的其他数据。新建索引就是新增一个B+树,查询不走索引就是遍历主B+树。                                                                                              (B/B+/B-/B*树相关:https://www.cnblogs.com/oldhorse/archive/2009/11/16/1604009.html、https://www.jianshu.com/p/486a514b0ded)

2、根据叶子节点的内容,索引类型分为主键索引和非主键索引。主键索引的叶子节点存的是整行数据。在InnoDB里,主键索引也被称为聚簇索引(clustered index)。非主键索引的叶子节点内容是主键的值。在InnoDB里,非主键索引也被称为二级索引(secondary index)。

3、基于主键索引和普通索引的查询的区别:

        主键查询方式,则只需要搜索ID这棵B+树;普通索引查询方式,则需要先搜索k索引树,得到主键的值,再到主键的索引树搜索一次。这个过程称为回表(回到主键索引树搜索的过程)。也就是说,基于非主键索引的查询需要多扫描一棵索引树。因此,我们在应用中应该尽量使用主键查询。注意:没有主键的表,InnoDB会给默认创建一个Rowid做主键

三、索引维护:

1、页分裂:B+树为了维护索引有序性,在插入新值的时候需要做必要的维护。当一个数据页满了,按照B+Tree算法,新增加一个数据页,然后挪动部分数据过去。这步叫做页分裂,会导致性能下降。空间利用率降低大概50%。当相邻的两个数据页由于删除了数据,导致利用率很低的时候会做数据页合并,合并的过程是分裂过程的逆过程。

2、自增主键:是指自增列上定义的主键,在建表语句中一般是这么定义的: NOT NULL PRIMARY KEY AUTO_INCREMENT。插入新记录的时候可以不指定主键的值,系统会获取当前主键最大值加1作为下一条记录的主键的值。

3、应该使用自增主键的场景:从性能的角度考虑,自增主键的插入数据模式,符合了“递增插入”的场景。每次插入一条新记录,都是追加操作,都不涉及到挪动其他记录,也不会触发叶子节点的分裂。而有业务逻辑的字段做主键,则往往不容易保证有序插入,这样写数据成本相对较高。从存储空间的角度考虑,假设表中有一个唯一字段,比如字符串类型的身份证号,那应该用身份证号做主键,还是用自增字段做主键呢?由于每个非主键索引的叶子节点上都是主键的值。如果用身份证号做主键,那么每个二级索引的叶子节点(主键的值)占用约20个字节,而如果用整型做主键,则只要4个字节,如果是长整型(bigint)则是8个字节。显然,主键长度越小,普通索引的叶子节点就越小,普通索引占用的空间也就越小。所以,从性能和存储空间方面考量,自增主键往往是更合理的选择。

4、不应该使用自增主键场景:只有一个索引且该索引必须是唯一索引。你一定看出来了,这就是典型的KV场景。由于没有其他索引,所以也就不用考虑其他索引的叶子节点大小的问题。此时应该优先考虑“尽量使用主键查询”原则,直接将这个索引设置为主键,可以避免每次查询需要搜索两棵树。

四、覆盖索引:

1、由于覆盖索引可以减少树的搜索次数,显著提升查询性能,所以使用覆盖索引是一个常用的性能优化手段。

2、最左前缀原则:先要看第一列的索引项,在第一列满足的条件下再看左边第二列的索引项,以此类推。索引项是按照索引定义里面出现的字段顺序排序的。只要满足最左前缀,就可以利用索引来加速检索。这个最左前缀可以是联合索引的最左N个字段,也可以是字符串索引的最左M个字符。

3、在建立联合索引的时候,安排索引内的字段顺序的原则:评估标准是,索引的复用能力。因为可以支持最左前缀,所以当已经有了(a,b)这个联合索引后,一般就不需要单独在a上建立索引了。所以, 第一原则是,如果通过调整顺序,可以少维护一个索引,那么这个顺序往往就是需要优先考虑采用的。如果既有联合查询,又有基于a、b各自的查询呢?查询条件里面只有b的语句,是无法使用(a,b)这个联合索引的,此时不得不维护另外一个索引,也就是说需要同时维护(a,b)、(b) 这两个索引。这时候,我们要考虑的原则就是空间了。比如上面这个情况,a字段是比b字段大的 ,此时建议创建一个(a,b)的联合索引和一个(b)的单字段索引。

五、索引下推:

1、概念:可以在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。(MySQL 5.6 引入)。比如说,检索出表中“名字第一个字是张,而且年龄是10岁的所有男孩”。(mysql> select * from tuser where name like '张%' and age=10 and ismale=1;),无索引下推时,这个过程InnoDB并不会去看age的值,只是按顺序把“name第一个字是’张’”的记录一条条取出来回表。因此,需要回表所有姓张的人数。InnoDB在(name,age)索引内部就判断了age是否等于10,对于不等于10的记录,直接判断并跳过。只需要对符合条件的记录回表取数据判断,回表次数等于符合条件的人数,小于等于无索引下推时的回表次数。

你可能感兴趣的:(MySQL实战45讲Day04----索引)