当前位置: 首页 > 科技观察

面试官问我为什么指数这么快?好像没解释清楚

时间:2023-03-22 16:52:20 科技观察

阿粉,相信大家一定知道,在数据库中加入一定数量的索引,会让你的查询语句从原来的3秒缩短到零点几秒,但是很多人不知道为什么要加索引。为什么你的查询语句加了索引就跑了?今天阿芬就来说说指数。Indextype(common)Primarykeyindex(主键):主键索引这个范从第一次接触开发开始就被各种灌输。表的主键默认是索引,不允许空值。普通索引(index/normal):MySQL中的基本索引类型,没有任何限制,允许在定义索引的列中插入重复值和空值。全文索引(fulltext):全文索引只能在文本类型CHAR、VARCHAR和TEXT的字段上创建。全文索引在MyISAM和InnoDB中都可用。唯一索引(unique):索引列中的值必须是唯一的,但允许空值。索引的类型绝对不限于这些项目。现在我们知道了分类,让我们来看看如何创建不同的索引。如何创建不同的索引其实如果你真的不会写SQL创建索引,最简单的就是Navicat,你总会用到的,一定要懂图形界面操作,那么直接图形化操作就可以了还不够好。这样的操作是不是简单明了?选择你要创建的索引类型,然后命名你要创建索引的字段,最后给它加上注释,这是一个完美的解决方案,但我们仍然需要写一个语句才能看到它。1.创建一个普通索引ALTERTABLEtable_nameADDINDEXindex_name(column)比如我们有一个表叫user,我们想给user表中一个叫phone的字段加索引。我们应该怎么写呢?ALTERTABLEuserADDINDEXphoneIndex(phone)这时候我们就创建了一个索引,索引的删除比较简单。其实创建索引其实就是给我们原表中的某个字段添加索引。这个大家一定要清楚,不要和Create搞混了。下面,阿芬就简单的给大家称之为创作吧。ALTERTABLEtestalter_tb1DROPINDEXindex_name删除我们刚刚创建的索引是ALTERTABLEuserDROPINDEXphoneIndex然后我们可以看到删除成功了。>OK>时间:0.012s2。创建唯一索引(unique)并删除ALTERTABLEuserADDuniquephoneIndex(phone)ALTERTABLEuserDROPINDEXphoneIndex;不要想当然的认为我在创建的时候指定了索引的类型,然后在删除phoneIndex的时候执行一个ALTERTABLEuserDROPunique;阿芬亲自试了试,果然没有成功。3、创建主键索引(primarykey)和删除ALTERTABLEuserADDPRIMARYKEY(phone):ALTERTABLEuserDROPPRIMARYKEY一般我们在建表的时候都会建这个主键索引,所以用到的场景不多。4.创建全文索引(fulltext)并删除。创建方法和ALTERTABLEuserADDFULLTEXTphoneIndex(phone)ALTERTABLEuserDROPINDEXphoneIndex几乎一样;既然了解了创建方法,是不是应该回归主题,说说为什么使用索引会更快,这就不得不涉及到索引的底层知识了。在没有索引的情况下,我们只能从头到尾逐行查找数据。每一行数据查找意味着我们要到磁盘的相应位置去读取获取一条数据。如果查询一条数据分为两步:查询磁盘和比较查询条件,那么查询磁盘的时间会比比较查询条件的时间长很多,也就是说在一次查询中,磁盘IO占用了很多时间。此外,查询的效率取决于磁盘ios的数量。如果我们能在一次查询中尽可能地减少磁盘ios的数量,那么我们就可以加快查询速度。那么我们就开始介绍索引,然后分析索引底层是如何快速实现查找的。实际上,索引的底层其实是一棵树,即B-tree和B+树,也可以称为变种B+树。大家也都知道,Mysql中最常用的引擎,比如InnoDB、MyISAM,最后都选择了B+树作为索引。然后说说这个B树和B+树。B-tree,又称B-tree,是一种平衡的多叉树(可以类比为平衡二叉搜索树),更适合外部搜索。画一棵二阶B树:second-orderB-tree那么为什么我们称它为二阶B树呢?这个顺序其实就是一个节点最多有几个子节点。在我们上图中,X元素有2个子节点,A元素有2个子节点C和D,B元素有2个子节点EF,也就是说一个节点最多有多少个子节点,我们称它为数阶树,通常这个值用m来表示。注意我们说的,就是一个节点上子节点的最大个数。如果有一个分支有三个节点,一个分支有两个节点,那么我们称它为三阶B树。m阶B树必须满足什么条件?每个节点最多可以有m个子树。根节点,至少只有2个节点(或者极端情况下,一棵树只有一个根节点,单细胞生物就是根、叶、树)。非根非叶节点至少有Ceil(m/2)个子树(Ceil表示向上取整,图中3阶B树,每个节点至少有2个子树,即至少有2个叉子)。非叶子节点中的信息包括[n,A0,K1,A1,K2,A2,...,Kn,An],其中n表示该节点存储的关键字个数,K为关键字,Ki为来自roottoleaf的每条路径长度相同,即叶子节点在同一层,这些节点没有信息。实际上,这些节点表示找不到指定的值,即指向这些节点的指针为空。B树的查询过程与二叉排序树类似。每个节点从根节点开始依次比较,因为每个节点和左右子树中的关键字是有序的,所以只需要比较节点中的关键字,或者沿着指针快速找到指定的关键字即可。如果查找失败,则返回叶节点,即空指针。B树搜索的简单伪算法如下:BTree_Search(node,key){if(node==null)returnnull;foreach(node.key){if(node.key[i]==key)returnnode.data[i];if(node.key[i]>key)returnBTree_Search(point[i]->node);}returnBTree_Search(point[i+1]->node);}data=BTree_Search(root,my_key);这是一个伪算法,写得不好,请见谅,那什么是B+树呢?B+树是一种树型数据结构,它是一棵n叉树,每个节点通常有多个子节点,一棵B+树包含根节点、内部节点和叶节点。根节点可以是叶节点,也可以是包含两个或多个子节点的节点。B+树常用于数据库和操作系统的文件系统。NTFS、ReiserFS、NSS、XFS、JFS、ReFS、BFS等文件系统都使用B+树作为元数据索引。B+树的特点是可以保持数据稳定有序,其插入和修改具有比较稳定的对数时间复杂度。B+树元素自下而上插入。B+树比较显着的特点是什么?每个父节点的元素出现在子节点中,是子节点中最大或最小的元素。在上面的树中,根元素8是子节点258的最大元素,根元素15也是。此时需要注意的是,根节点的最大元素相当于整个B+树的最大元素.无论以后如何插入或删除,最大的元素必须始终保留在根节点中。叶子节点,因为父节点的元素出现在子节点中,所以所有的叶子节点都包含了全量的元素信息。B+树和B树的区别在于,一个有k个子节点的节点必须有k个元素。非叶子节点仅作为索引,与记录相关的信息存储在叶子节点中。树的所有叶子节点组成一个有序链表,可以按元素排序排序的顺序遍历所有记录。B-tree和B+树的区别在于B+树的非叶子节点只包含导航信息,不包含实际值。所有的叶子节点和相连的节点都通过一个链表连接起来,方便区间搜索和遍历。说到这里,有的读者会开始想,说了半天没说到点子上,为什么加索引会更快呢?刚才阿芬也说了数据库通过IO从磁盘读取数据。操作,一次磁盘IO操作可以取出物理存储中的一大块相邻数据,如果要查询的索引数据(即B+树中从根节点到叶子节点查询的节点个数)是都集中在这个区域,那么只需要一次磁盘IO,否则需要多次磁盘IO。是不是比较简单明了?再举个简单的例子:比如我们要查询user表中名字为xiaohong的数据,我们写SQL的时候,select*fromuserwherename='xiaohong',如果此时没有索引,数据库直接把全表的数据全部扫描一次,然后找name='xiaohong'的数据,我们给它加上索引后,我们就用索引搜索来查询'xiaohong'这个数据,因为索引已经按照字母顺序排列了,所以我们要查找名为“xiaohong”的数据会更快的被记录下来。你明白吗?它就像一本字典。我给你列出所有x开头的数据,然后你从x开头的数据中搜索。你直接不做任何处理,只是一页一页地翻字典。速度,哪个更快,相信大家都明白。