背景
Mysql无疑是互联网公司用的最多的数据库了,它拥有开源、免费、学习成本低((#_<-))等优点,以至于被各大厂商青睐。理论上来说作为开发人员而不是专业的DB人员只需要掌握常用的增删改查命令以满足业务需求就行。不过,由于互联网行业的兴起,导致了公司的业务越来越复杂,数据量越来越庞大,再加上程序员这一职业越来越受到人们的青睐,许多人纷纷通过各大培训机构转行,就连考研学子也称计算机专业为“宇宙机”,纷纷选择跨专业考研。
无疑是这一越来越内卷的现象,催生了众多公司对开发人员Mysql越来越高的要求。如今,随便上某招聘网站搜索“Java开发工程师”职业要求,其中数据库一栏基本都是:熟练使用数据库,精通数据底层原理,索引数据结构,sql优化......
当我第一次看到这些,心里一万个草泥马,你这是在招DB还是Java开发?我就会个增删改查还不行吗?
如果你也有相似的经历,对Mysql还只停留在增删改查阶段,想要轻松通过Mysql相关面试或者单纯的想提升自己的sql认知水平。相信本文会带给你耳目一新的感觉。
Ps 本人虽然科班出身,却非常排斥满文专业术语让人一头雾水,所以全文我会尽量用大白话形式展现,在必要的时候会有自己的绘图以辅助让文字更容易理解
从Mysql的引擎说起
存储引擎是Mysql的核心,Mysql的存储引擎是以插件的形式运行的,所以诞生了许多存储引擎,如InnoDB、MyISAM、MEMORY、ARCHIVE、CSV等十多种。
不过从mysql5.5开始,默认存储引擎就已经是InnoDB了,在之前是MyISAM,而我们仅仅只需要掌握这两种就行(重点还是InnoDB)
MyISAM存储引擎:
作为mysql5.5以及之前的默认引擎,它具有以下特点:
(1)不支持事务;
(2)不支持外键,如果强行增加外键,不会提示错误,只是外键不其作用;
(3)对数据的查询缓存只会缓存索引,不会像InnoDB一样缓存数据,而且是利用操作系统本身的缓存;
(4)默认的锁粒度为表级锁,所以并发度很差,加锁快,锁冲突较少,所以不太容易发生死锁;
(5)支持全文索引(MySQL5.6之后,InnoDB存储引擎也对全文索引做了支持),但是MySQL的全文索引基本不会使用,对于全文索引,现在有其他成熟的解决方案,比如:ElasticSearch,Solr,Sphinx等。
(6)数据库所在主机如果宕机,MyISAM的数据文件容易损坏,而且难恢复;
InnoDB存储引擎
随着软件行业的不断发展,尤其是互联网行业的兴起,以前的存储引擎完全无法满足业务需求,所以Mysql在5.5版本后就以此存储引擎作为默认。InnoDB作为一款经典的存储引擎,它能够适应绝大多数企业的用途。
主要特点有:
(1)灾难恢复性比较好;
(2)支持事务。默认的事务隔离级别为可重复度,通过MVCC(并发版本控制)来实现的。
(3)使用的锁粒度为行级锁,可以支持更高的并发;
(4)支持外键;
(5)配合一些热备工具可以支持在线热备份;
(6)在InnoDB中存在着缓冲管理,通过缓冲池,将索引和数据全部缓存起来,加快查询的速度;
(7)对于InnoDB类型的表,其数据的物理组织形式是聚簇表。所有的数据按照主键来组织。数据和索引放在一块,都位于B+数的叶子节点上;
你真的会建表吗?
对于绝大多数程序员,每天的工作无疑都是对数据库进行“增删改查”。而表是我们存储数据的核心,如果能够根据业务建立一张合适的数据表,不仅能够提升我们的开发效率,还会一定程度使数据库查询效率更高。
关于建表规范,推荐阿里巴巴数据库设计规范:[阿里巴巴MySQL数据库设计规范](数据库设计规范-阿里云开发者社区 (aliyun.com))
彻底说透索引
到底什么是索引?
对于索引,我相信绝大多数人都知道,也都用过。而且一般都会认为索引就相当于是书籍的目录,可以方便我们快速查找数据。然而这样认为并不完全正确。
索引应该是帮助MySQL高效获取数据的排好序的数据结构。
没错,索引就是一种数据结构,包括:
- 二叉树,一种子节点最多为两个的树形数据结构。
- 红黑树,一种从根节点到任意尾节点的路径之差不超过1的平衡二叉树
- 哈希表,一种通过哈希算法直接存储内存地址的数组
- B树,一种在节点存储多条索引元素以及附带数据的树形结构
- B+树,B树的变种,冗余存储了索引元素,在叶子节点存储了所有索引元素和附带数据,且含有双向指针
那么,索引到底是保存的什么呢?
一个完整的索引数据通常包含两部分:排序的值和对应的数据
通常索引会按照索引字段进行排序并存储
会根据编码类型和排序规则进行排序,在我们创建数据库时可以指定。
图
索引的数据具体保持的什么需要视情况而定,存储引擎的不同以及索引类型的不同都会导致索引数据存储的方式和结果不同
在MyISAM存储引擎中,主键索引对比非主键索引只有重复与否的区别,主键索引的值不可重复。所有索引存储的数据其实是磁盘文件地址(数据结构同样是B+树,这种索引也称为非聚族索引)。
但寻找到相应的索引后,就会根据磁盘文件地址寻找相应的真实数据并加载到内存中。
而在InnoDB存储引擎中,如果是主键索引,那么在索引的数据区就是存储这一行对应表中完整的数据。如果是非主键索引,那么数据区就是存储的主键索引地址。
显而易见,InnoDB的主键索引虽然冗余了大量的数据,但减少了磁盘IO操作,也就提升了查询效率,而这种索引也被称为聚族索引。当我们根据主键索引查询数据时,很显然直接就从磁盘查询到了,而根据非主键索引查询数据时,需要额外查询一次主键索引。
常见疑问🤔️:
-
聚族索引既然冗余了这么多数据,那么进行增删改操作岂不是不好维护?
得确,聚族索引在维护时需要进行额外的操作。但通常来说,一个表的数据查询的次数是要远远高于修改的次数,综合考虑,维护成本带来的收益还是相当可观的。
-
为什么InnoDB引擎推荐每个表都需要有主键,并且最好时整型的自增主键?如果不建主键怎么样?
首先,InnoDB并不强制需要用户建立主键,但它得确是必须存在主键的,当你没创建主键时,mysql会选择表中唯一的字段作为主键;若当你没有唯一字段时,mysql会根据你的插入顺序(俗称行数)来作为主键。
因为索引是根据索引字段来排序插入的,作为一颗B+树来维护,既然排序,肯定整型自增的类型是天然排序的;如果不是整型,比如字符型,那么mysql就会根据字符编码和排序规则来排序,对比整型可以直接排序相当于是多了一个步骤。
-
主键索引是必须的吗?
主键索引是必须的,它是跟主键相与相存的,并且一般由mysql自动创建。
-
聚族索引相比非聚族索引谁快,为什么?
聚族索引要更快,因为聚族索引可以直接在一个磁盘文件中寻找到索引数据,而非聚族索引需要跨文件寻找完整数据(俗称“回表”)。
-
在建立索引时我们还可以选择hash索引,为什么一般很少用,它有使用场景吗?
hash索引数据结果类似于Java的HashMap,也会存在哈希碰撞。查询效率通常来说比B+树更高,但是只适合查找“=”,范围类查找无法使用该类型索引。如果一张表的需求只会有等值查询可以考虑哈希索引(这种需求应该很少吧)。
-
B+树类索引是否支持范围查找,原理如何?
B+树支持范围查找,原理见下图,我相信你会一目了然。。。
图
为什么需要索引?
通常来说在没有缓存和索引的情况下,Mysql查找任何数据都是读取磁盘文件进行IO操作,并进行逐行扫描,直到查找到目标数据。在数据量很大或关联查询较复杂的情况下会极大的影响查询效率。
而索引作为一种有序并且查询效率极高的数据结构,可以快速的查找目标数据。