一、引言
MySQL是目前互联网公司常用的数据库之一,几乎所有业务都离不开对数据的操作,那么对于数据查询来说,索引又是一个绕不开的话题,所以这篇文章开始从新认识一下MySQL的索引,也便于我们日后对于一些SQL的优化事半功倍。
二、索引
定义:索引是帮助MySQL高效获取数据的排好序的数据结构
索引数据结构:
PS:对应数据结构我也写有学习笔记,有需要的码友们可以点击后面的链接了解下,如有写的不对的地方还望指正,共同进步,感谢!共勉??
MySQL的索引:B+树
MyISAM存储引擎建表结构
根据上图我们可以看到,如果用MyISAM这种储存引擎建表的话,索引文件和数据文件是存放于2个文件下的,所以使用MyISAM储存引擎建表时,索引类型为非聚集索引,这也就引出2个概念:
- 非聚集索引:索引文件和数据文件是分离的【MyISAM】
- 聚集索引:叶节点包含了完整的数据记录【InnoDB】
InnoDB存储引擎建表结构
根据上图我们可以看到,如果用InnoDB这种储存引擎建表的话,索引文件和数据文件是存放于同一个文件下的,叶子节点包含了完整的数据记录【MySQL用B+树保存索引,而B+树叶子节点组成的链表包含了树上的所有数据】,所以使用InnoDB储存引擎建表时,索引类型为聚集索引。
PS:InnoDB表只会有一个聚集索引【有主键就用主键,没有的话MySQL就使用rowid之类的作为聚集索引】,其他新建的二级索引都是非聚集索引!
三、小问答
Q:B+树为啥在B树的基础上把数据放到叶子节点才进行存储?
为了在非叶子节点中存储更多元素,使得树的高度减少。【查询耗时主要是每次读取数的当前层时,磁盘I/O的耗时】
PS:B+树的高度是由非叶子节点中能放多少个索引元素决定的。
Q:存储引擎是形容数据库还是数据表的?
形容数据表。
Q:为什么建议InnoDB表必须建主键?
因为MySQL索引需要一列完全不重复的数据来生成一棵B+树:
- 1、避免mysql去挑表中所有数据不重复的一列当作索引列【没有主键就得一列一列找看有没有重复的,你说死不死....】
- 2、如果所有列都存在数据重复的情况,则mysql会创建一个隐藏列【如rowid列】,有主键的话,这个操作也可以避免
PS:首先表就应该有个主键作为数据的唯一标识,而且本来新建一列就能解决的问题,让mysql去做那么繁杂的事情,不合适。
Q:为什么主键推荐用自增不用UUID?
还是回到B+树索引的问题上,如果是自增形式的话,就很好进行排序,但是如果是uuid的话,那要根据ASCII码来逐位比较才能创建索引,万一是最后几位才发现不一样,那可不慢死了...
Q:为啥主键要选用自增的形式?
1、非自增的话当先插入一个大的元素再插入一个小的元素则可能引起原来的非/叶子节点重新分裂【大节点变成小节点,比如节点(5,6,8),插入元素7则可能被优化成(5,6)(7,8)两个节点,甚至可能需要对整个树进行平衡】,影响效率。
2、由于innoDB储存引擎只允许有一个聚集索引,如果不用主键【默认就是索引】递增的方式,那么我们自己建的索引【二级索引】的叶子节点存放的就不是整行数据了,而是rowid之类的能唯一区分当前行的元素。【之所以不存储整行数据,是为了保证一致性和节省空间,毕竟总不可能建立了几个二级索引,就把表的数据复制几份】
PS:二级索引也是非聚集索引,它储存的是行的唯一标识【主键或者rowid之类的唯一标识】,再查找过程中得到这个唯一标识以后,还要去主键索引【没有的话就全表扫描】去找到对应的行内容才能取出当前行的数据。
Q:聚集索引和非聚集索引哪个查找效率更快?
聚集索引更快,因为数据直接存储在叶子节点,而非聚集索引的叶子节点存的是内存地址,还需要拿这个内存地址去跨文件搜索【回表】,效率肯定比不上聚集索引。
Q:什么是最左前缀原理?
最左前缀原理主要是针对联合索引引申的概念,我们通过一张图来分析:
那么有如下sql语句,哪些是可以用上索引的呢?
select * from t_user where name = ‘有梦想的肥宅‘ and age = 27; 【可以使用索引】 select * from t_user where age = 27 and profiles = ‘dev‘;【无法使用索引】 select * from t_user where age = 18;【无法使用索引】
原因:建立联合索引的时候就是根据字段顺序来给索引排序的,所以使用索引时也必须要按照联合索引字段的顺序来进行查询条件的设置。