面试的时候肯定会问这一个问题,mysql为什么会选择b+树作为索引呢?而不选择其他索引,例如b树?hash?
创新互联服务项目包括肃州网站建设、肃州网站制作、肃州网页制作以及肃州网络营销策划等。多年来,我们专注于互联网行业,利用自身积累的技术优势、行业经验、深度合作伙伴关系等,向广大中小型企业、政府机构等提供互联网行业的解决方案,肃州网站推广取得了明显的社会效益与经济效益。目前,我们服务的客户以成都为中心已经辐射到肃州省份的部分城市,未来相信会继续扩大服务区域并继续获得客户的支持与信任!
下面说的磁盘IO是指数据从硬盘加载到内存中的操作
hash索引的话,不支持范围查询,因为hash就是一个键对应一个值的,没办法范围查询
二叉树的话,它的特点就是左子树小于根节点小于右子树,如果根节点取值有问题的话,有可能会退化成链表,就是树不分叉了,树一直往左或者一直往右,这样就不能折半查找从而减少IO次数了,不支持范围查询,要是范围查询的话,每次都要从根部遍历,树也太高了,树越高,IO操作越频繁,浪费资源
平衡二叉树的话,它就没有了二叉树的这种退化成链表的缺点,因为他左右子节点最多相差1层,可是他也不支持范围查找这一点和二叉树的问题一样
b树的话,和二叉树比起来树是很矮胖,IO操作减少了,是个多叉树,它每个节点都存了对应的行数据,可是如果这一行的数据的列不断的增加,那么这一页存储的节点就会变少,因为所占的空间不断的变大,树也会越来越高,增加IO操作次数,同时是也不支持范围查找。要是相同大小的空间可以存很多的节点数据的话就更好了,所以就有了下面的b+树
b+树 它非叶子节点只存索引的数据,不存整行数据,但是叶子节点是冗余的,冗余了非叶子节点,叶子节点还都用双向链表链接起来,这样有助于顺序查找,b+树和b树比起来,更加矮胖,磁盘IO次数更少
二、 mysql中索引类型
聚簇索引与非聚簇索引
我们可以简单的理解为 聚簇索引就是主键索引,非聚簇索引就是普通索引
本质的区别是
聚簇索引的叶子节点存储的是整行数据
innodb是通过主键来实现聚簇索引的,如果没有主键的话,那么他就会选择一个唯一非空的索引来实现,如果再没有的话,他就会隐式生成一个主键来实现聚簇索引
非聚簇索引存储的是索引值和主键值
普通索引 一张表中可以有多个普通索引,随便一个字段都可以建立的索引,我们平常建立的索引大部分都是普通索引
联合索引 好几个字段联合起来建立的索引
唯一索引 业务中唯一的字段适合建立唯一索引,一个表中可以有多个唯一索引
主键索引 和唯一索引一样,主键索引也是唯一的,不同的就是,一个表只能有一个主键索引
三、关于索引的sql
创建主键索引
ALTER TABLE test add PRIMARY KEY (id)
创建唯一索引
ALTER TABLE test add UNIQUE idx_id_card(id_card)
创建普通索引
ALTER TABLE test add INDEX idx_name(name)
创建联合索引
ALTER TABLE test add INDEX idx_age_name(age,name)
修改索引名称 :先删除再添加
删除索引 (两种方式)
两者的算法思路其实很像:比中间的小就在剩下的左边,大就在剩下的右边找 但是: 二叉树查找一般习惯是在链式存储上进行,为一个树形结构 二分查找一定在顺序存储上进行
文就是对这两种数据结构做简单的介绍。
1. B-Tree
B-Tree不是“B减树”,而是“B树”。
这里参考了严蔚敏《数据结构》对B-Tree的定义:
一棵m阶的B-Tree,或者为空树,或者满足下列特性:
1.树中每个结点至多有m棵子树;
2.若根结点不是叶子结点,则至少有两棵子树;
3.除根节点之外的所有非终端结点至少有[m/2]棵子树;
4.所有非终端结点中包含下列信息数据:
(n,A0,K1,A1,K2,A2……Kn,An)
其中,n为关键字的数目,K(i)为关键字,且K(i) K(i+1), Ai为指向子树根结点的指针,且指针A(i-1)所指子树中所有结点的关键字均小于Ki,Ai所指子树中所有结点的关键字均大于Ki;
5.所有叶子结点都出现在同一层次上;
下面通过一个例子解释一下B-Tree的查找过程。
这是一棵4阶的B-Tree,深度为4。
假如在该图中查找关键字47,首先从根结点开始,根据根结点指针t找到*a结点,因为47大于 *a 结点的关键字35,所以会去A1指针指向的 *c结点继续寻找,因为 *c的关键字 43 要查找的47 *c结点的关键字78,所以去 *c结点A1指针指向的 *g结点去寻找,结果在 *g结点中找到了关键字47,查找成功。
2. B+Tree
不同的存储引擎可能使用不同的数据结构存储,InnoDB使用的是B+Tree;那什么是B+Tree呢?
B+Tree是应文件系统所需而出的一种B-Tree的变型树,一棵m阶的B+树和m阶的B-树的差异在于:
1.有n棵子树的结点中含有n个关键字;
2.所有的叶子结点中包含了全部关键字的信息,及指向含这些关键字的记录的指针,且叶子结点本身依关键字的大小自小而大顺序链接;
3.所有的非终端结点可以看成是索引部分,结点中仅含有其子树(根结点)中的最大(或最小)关键字;
还是通过一个例子来说明。
这个例子中,所有非终端结点仅含有子树中最大的关键字。
因为叶子节点本身依据关键字的大小自小而大顺序链接,所以可以从最小关键字起顺序查找。也可以从根结点开始,进行随机查找。
在B+树中随机差找和在B-树中类似,以上图为例。假设要查找关键字51,现在根节点中比较,发现5159,因为这里使用的是非终端结点的关键字是子树中最大的关键字,所以进入最大值为59的子结点(15\44\59)中查找,同理,因为445159,所以进入P3指向的结点(51\59)中查找,然后命中关键字51,因为此结点(51\59)是叶子结点,所以查找终止,该结点包含指向数据的指针。
3.索引如何在B+Tree中组织数据存储
假设有如下表:
对于表中的每一行数据,索引中包含了last_name、first_name和dob列的值,下图展示索引是如何组织数据存储的:
索引对多个值进行排序的依据是定义索引时列的顺序。
(Allen Cuba 1960-01-01)结点左侧的指针指向[?,Allen Cuba 1960-01-01)的叶子页,(Allen Cuba 1960-01-01)和(Astaire,Angelina,1980-03-04)之间的指针指向[Allen Cuba 1960-01-01,Astaire Angelina 1980-03-04)的叶子页,以此类推。总之,每个指针指向的结点中的最小值就是该指针左侧的的值。
这种存储结构也说明了在定义多个列组成的多列索引中,为什么需要把重复率最低的列放到最左侧,因为这会减少比较的次数,查找起来更加高效。
4.索引为什么选用B树这种数据结构?
因为使用B树查找时,所用的磁盘IO操作次数比平衡二叉树更少,效率也更高。
为什么使用B树查找所用的磁盘IO操作次数比平衡二叉树更少?
大规模数据存储中,树节点存储的元素数量是有限的(如果元素数量非常多的话,查找就退化成节点内部的线性查找了),这样导致二叉查找树结构由于树的高度过大而造成磁盘I/O读写过于频繁,进而导致查询效率低下。那么我们就需要减少树的高度以提高查找效率。而平衡多路查找树结构B树就满足这样的要求。B树的各种操作能使B树保持较低的高度,从而达到有效减少磁盘IO操作次数。
在二叉树中有一种平衡二叉树,通过平衡算法可以让二叉树两边的节点平均分布,这样就能让所有的索引查找都在一个近似的时间内完成。而MySQL这类数据库采用了二叉树的升级版B+Tree的形式,每个节点有三个支叶,不过其算法原理仍然是平衡树的原理。
MySQL(和PHP调配之***组合)的授权方法
MySQL(和PHP调配之***组合)选用两层授权(Dual Licensed),它们是GPL和MySQL数据库(和PHP调配之***组合) AB拟定的商业答应协议。
假如你在一个遵从GPL的自在(开源)项目中运用MySQL(和PHP调配之***组合),那么你能够遵从GPL协议运用MySQL(和PHP调配之***组合)。
可是,假如你的项目不是在GPL协议下的话,你有必要为运用MySQL(和PHP调配之***组合)来付出答应费用,或许你或许由于这个要素而将你的项目改为遵从GPL,那么你需求处理因而带来的更多的支撑作业,这有或许会带来本钱上的进步。在这种情况下,一些软件发行商或许倾向于挑选其他开源数据库,例如遵从BSD授权的PostgreSQL。
2、产品老练性
到2009年,甲骨文的数据库Oracle(大型网站数据库渠道)现已诞生了30周年,而MySQL(和PHP调配之***组合)却连它的一半时刻都没有。微软的sql server(WINDOWS渠道上强壮的数据库渠道)只是比MySQL(和PHP调配之***组合)大两年,可是sql server(WINDOWS渠道上强壮的数据库渠道)的发布是建立在Sybase的基础上,那时分Sybase现已诞生了6年的时刻。
至于其他值得重视的开源数据库,PostgreSQL将在2009年到达20岁的生日。虽然MySQL数据库(和PHP调配之***组合)并不是市场上最年青的数据库,可是却有更多老练的数据库可供咱们挑选。
当然,或许这并不是咱们回绝MySQL(和PHP调配之***组合)的一个有说服力的理由,可是关于一些比较保守的IT司理来说,在为一些要害事务挑选渠道的时分,渠道的老练性却是有必要要考虑的一个要素,在这一点上,MySQL(和PHP调配之***组合)无疑毫无优势。
3、功用设置老练性
要想在MySQL(和PHP调配之***组合)与其他数据库之间进行一个八面玲珑的功用设置比照,并不是一件简单的工作。跟着新软件版其他发布或一些补丁的推出,从前的功用列表或许会敏捷变得过期了。并且,有些功用对有的使用程序非常重要,可是对其他使用程序则不必定。
有的时分,一些缺失的功用能够通过其他方法来完成,例如,在MySQL(和PHP调配之***组合) 4.1曾经,你能够通过运
一般的数据备份用 :mysql路径+bin/mysqldump -u 用户名 -p 数据库名 导出的文件名
数据还原是:到mysql命令行下面,用:source 文件名;的方法。
但是这种方法对大数据量的表进行操作就非常慢。因为他不仅导出了数据还导出了表结构。
在针对大数据量的表时,我们可以用infile和 outfile来操作。
outfile导出数据库数据的用法:
下图我们可以看到6百多万数据35秒就搞定了:
下面我们看看infile的语法:
在infile导入数据的时候,我们还可以做一些优化。我们可以用
alter table table_name disable keys 关闭普通索引。等数据导入玩,再用:
alter table table_name enable keys 来开启普通索引。这样就不会边导入数据,边整理索引的二叉树儿影响导数据的效率。
如果可以保证 数据的正确性,我们可以将表的唯一索引也关闭,之后再开启,不是每条数据就算是唯一的他都要去检测一遍。命令:
set unique_checks=0; #关闭唯一校验
set unique_checks=1;#开启唯一校验
如果是InnoDB存储引擎,我们还可以set auto commit=0;关闭自动提交,来提高效率。InnoDB是按主键的顺序保存的,我们将其主键顺序排列也可以提高效率。
下面我们对myisam引擎的表做个测试,我们先不关索引,导入数据(用了近4分钟):
然后我们先把索引关闭试试(只用了一分钟多一点,快了不少啊!摸摸大!):