Mysql中的索引
1,什么是索引,为什么要使用索引?
索引是帮助Mysql高效获取数据的排好序的数据结构。建立索引可以帮助我们快速检索我们需要的信息,减少磁盘的I/O次数,加快检索速度。索引的数据结构包括:二叉树,红黑树,Hash表,B-树等。
2,数据查询的方式
二叉查找树的方式查找信息
普通情况下,在一个二叉树中查找到5非常快速。只需要2步,但在某些极端情况下,如对于顺序插入信息的二叉树,查找到我们需要的信息就非常麻烦了。
红黑树
红黑树是一种自平衡二叉查找树,就是会自动平衡更新根节点和其它节点的位置,也就是说根节点和其它节点的位置是不固定,会根据插入的信息进行动态改变的。
按照1~5的顺序插入数据后,会重新排列分支节点的位置。
对于少量数据使用红黑树是完全可以的,但是一个项目的数据库中存储的数据都是10万条以上,再使用红黑树,树的度又会变得很大了。这个时候就可以使用B 树了。
B 树
B树是一种多路自平衡搜索树,它是一种特殊的平衡二叉树,但B树允许每个节点有更多的子节点。B树示意图如下:
B树的特点:
(1)所有键值分布在整个树中(2)任何关键字出现且只出现在一个节点中
(3)搜索有可能在非叶子节点结束(4)在关键字全集内做一次查找,性能逼近二分查找算法
比如我们想要找到主键为28的数据,过程如下:
1,根据根节点找到磁盘块1,进行一次I/O(磁盘的输入和输出)操作;
2,比较关键字28在区间(17,35),发现位于两者之间,找到P2指针;
3,根据P2指针找到磁盘块3,再进行一次I/O操作;
4,比较关键字28在区间(26,30),发现位于两者之间,找到磁盘块3的P2指针;
5,根据P2指针找到磁盘块8,再进行一次I/O操作;
6,在磁盘块8找到主键为28的数据。
在上面的过程中,只进行了3次磁盘I/O操作和3次内存查找操作,与二叉树和红黑树相比,对磁盘和内存读写次数减少了很多。不仅如此,B树中的各个节点都是可以横向扩展的,也就是说,不管有多少条数据,获取我们想要的数据对磁盘和内存的读写不超过四次。而B树四层的深度就可以满足百亿左右数据的使用了。
虽然B树很不错,但由于数据的键和值都储存在B树中,而有些数据中不仅仅包含数字,还可能包含大文本或是图片的二进制文件。那么这个二叉树立马就大了起来。而一个索引一般情况下也只有16K(可以将索引看做是表中特殊的页,Mysql中一个页大小只有16K),导致原本能够容纳上亿信息量的B树由于数据过多无法横向扩展。B+树应运而生。
B+树
B+树是在B-树基础上的一种优化,使其更适合实现外存储索引结构,在B+树中,所有数据记录节点都是按照键值大小顺序存放在同一层的叶子节点上,而非叶子节点上只存储key值信息,这样可以大大加大每个节点存储的key值数量,降低B+树的深度。B+树示意图如下:
所有数据记录节点都是按照键值大小顺序存放在同一层的叶子节点上,而非叶子节点上只存储key值信息,这是B+树与B树最大的区别。并且B+树的叶子结点都是以双向链表的方式连接的,因此对整棵树的遍历只需要一次线性遍历叶子结点即可。而且由于数据顺序排列并且相连,所以便于区间查找和搜索。而B树则需要进行每一层的递归遍历。相邻的元素可能在内存中不相邻。叶子节点中的data区域存储的不是和key值有关的数据表的信息,而是信息所在的磁盘地址。现在大部分数据库的索引类型都是B+树类型。
3.索引的本质
索引就是一颗B+树,一种为了磁盘或是其它直接存取辅助设计的一种平衡查找树,所有记录节点按照键值顺序存放在同一层的叶子节点上。B+树的根节点存放在内存中,而非叶子节点和叶子节点存放在磁盘中,所以查找一条信息最多只需要进行3次磁盘I/O操作。
4,索引的分类
4.1、从数据结构
4.1.1 全文索引
FULLTEXT INDEX 是针对一篇文章或是字符的索引,全文索引和sql语句“where xx like xxx%”功能差不多,但是在大量的数据面前,使用全文索引查询速度更快。
目前,Mysql版本在5.6以上的版本,InnoDB和MyISAM存储引擎都支持全文索引,5.6以下版本只有MyISAM支持全文索引。
那么多少条信息可以使用全文索引呢。
MySQL 中的全文索引,有两个变量,最小搜索长度和最大搜索长度,对于长度小于最小搜索长度和大于最大搜索长度的词语,都不会被索引。通俗点就是说,想对一个词语使用全文索引搜索,那么这个词语的长度必须在以上两个变量的区间内。我们可以通过以下语句进行查询。
show variables like '%ft%';
MyISAM的最小和最大长度分别为4,84;而InnoDB的为3,84;只有长度在这个区间中的信息才能正常使用全文索引,反之则不会获取到信息。
虽然我们能够使用全文索引,但是MySQL的全文索引效率很低,一般我们通过都第三方工具代替,如Elasticsearch。
//创建全文索引create fulltext index getcontent on account(content);//删除全文索引drop index getcontent on account;alter table account drop index getcontent;
4.1.2 B+树索引
这类索引是各种数据库中最常见的索引结构,也是InnoDB使用的索引。
4.1.3 Hash索引
哈希索引(hash index)基于哈希表实现,只有精确匹配索引所有列的查询才有效。对于每一行数据,存储引擎都会对所有的索引列计算一个哈希码(hash code),哈希码是一个较小的值,并且不同键值的行计算出来的哈希码也不一样.由于生成的哈希码是随机的,所以无法进行范围查找,只能进行等值比较查询,也就是只能进行=,!=,in,not in等操作。
4.1.4 R树索引
R树索引也被称为空间树索引。用于解决索引地理坐标,很好的解决了在高维空间搜索等问题。但在MySQL中不存在,其它数据库存在如SQLite。
4.2、从逻辑角度
4.2.1 非空索引
要求数据不能为空或是null。
alter table account add constraint CN_Cons check( content is not null)
4.2.2 唯一索引
要求数据内容不重复,但是可以为空或是NULL,但只能有一个NULL和一个空。
creatre unique index con account(content)
4.2.3 主键索引
是一种特殊的唯一索引,并且不能有空值
4.2.4 复合索引
用户可以在多个列上建立索引,叫复合索引。
create index ico on table1(id,name,content);
对于复合索引,在查询使用时,最好将条件顺序按找索引的顺序,这样效率最高;
select * from account where id= A and name= B and content= C;//会使用复合索引select * from account where user= B and content= C;//不会使用复合索引
复合索引遵循最左匹配原则,即 where id=A and name=B可以用到索引,而 where name=B and content=C是不会用到复合索引的。因为B+树是按照数据库字段从左到右的顺序来建立搜索树的,B+树会优先比较id来确定下一步的所搜方向,如果id相同再依次比较name和content,最后得到检索的数据;但当查询语句没有id的数据的时候,B+树就不知道下一步该查哪个节点,因为建立搜索树的时候id就是第一个比较因子,必须要先根据id来搜索才能知道下一步去哪里查询。而如果缺少中间查询字段user时,数据库会先把id相同的信息查询到,然后在匹配content是C的数据。
4.3、从物理存储角度
4.3.1 聚簇索引
聚簇索引主要用于InnoDB表,数据表中的数据就是按顺序存储的,在物理上是连续的。将数据存储与索引放到了一块,因此一个表只能有一个聚簇索引。
我们在建立数据表时,会生成两个索引,主键索引和辅助索引;其中主键索引是根据主键自动生成的,如果没有主键索引,会自动将数据表中第一个唯一且非空的索引作为主键索引,如果还是没有会自动创建一个隐藏的名字为“GEN_CLUST_INDEX
”的聚簇索引。总之,一个 InnoDB 表只有一个聚簇索引,而且一定会有一个聚簇索引,如果不存在,Innodb 存储引擎会自动添加一个。而辅助索引则是我们人为建立的索引,也称为非聚簇索引。
通过其它字段建立的辅助索引的每条记录中都包含了该条记录的主键,主键索引的叶子节点包含了该主键所对应的数据信息。当我们根据某些条件查询数据时,会在辅助索引中获取满足查询条件的主键,然后使用主键检索到与之对应的叶子节点取得数据。
为什么辅助索引要使用主键作为‘指针’,而不用磁盘地址值作为’指针‘呢?
那是因为我们在进行行移动或者分裂数据页时(数据存储的位置发生变化),不需要更新辅助索引中的这个‘指针’。不管这个主键B+树的节点如何变化,辅助索引树都不受影响。
4.3.2 非聚簇索引
非聚簇索引主要用于MyISAM表,将数据存储与索引分开储存,非聚簇索引中也有主键索引和辅助索引,两个索引的储存位置是独立的,通过辅助键检索无需访问主键的索引树。虽然两个索引的结构看起来差不多,但是主键索引的叶子节点储存的是主键信息,而辅助索引的叶子节点储存的是辅助键,对于数据表来书没有任何差别,都是通过叶子节点直接获取到数据信息。所以对于MyISAM表,主键不是必须的。
4.3.3 区别
从上面来看,非聚簇索引比聚簇索引看起来要方便,非聚簇索引只要检索一次,而聚簇索引要检索两次,那么我们为什么还要使用聚簇索引呢?
这是因为聚簇索引中的主键索引和人为建立的辅助索引(非聚簇索引)都储存在一起的,当我们第一次访问这个表时,数据表的所有索引都已经加载到Buffer(缓冲区)了,之后再根据其它字段查询访问时,会在内存中完成,不必访问磁盘。节省了大量时间。而且按顺序存储的数据表要进行排序时,使用聚簇索引更加适合。同理,取出一定范围数据的时候,要使用聚簇索引。
当然,聚簇索引也有一定的缺点:
1.因为数据表的数据存储地址都是顺序的,所以更新聚簇索引列的代价很高,会强制将每个被更新的数据行移动到新的位置。
2.聚簇索引可能导致全表扫描变慢,尤其是行比较稀疏,或者由于页分裂导致数据存储不连续的时候。
3,如果主键比较大的话,那辅助索引将会变的更大,因为辅助索引的叶子存储的是主键值;过长的主键值,会导致非叶子节点占用占用更多的物理空间。
5,使用场景
1、不要索引数据量不大的表,对于小表来讲,表扫描的成本并不高。
2、不要设置过多的索引,在没有聚集索引的表中,最大可以设置249个非聚集索引,过多的索引首先会带来更大的磁盘空间,而且在数据发生修改时,对索引的维护是特别消耗性能的。
3、合理应用复合索引,有某些情况下可以考虑创建包含所有输出列的覆盖索引。
4、对经常使用范围查询的字段,可能考虑聚集索引。
5、避免对不常用的列,逻辑性列,大字段列创建索引。