首页 » SEO优化 » php字典索引技巧_MySQL详解索引的介绍和事理分析

php字典索引技巧_MySQL详解索引的介绍和事理分析

访客 2024-12-11 0

扫一扫用手机浏览

文章目录 [+]

实质上,索引的目的是为了提高查询效率,通过不断地缩小想要获取数据的范围来筛选出终极想要的结果,同时把随机的事宜变成顺序的事宜,也便是说,有了这种索引机制,我们可以总是用同一种查找办法来锁天命据。

可以类比银行的保险柜,比如你要找归属你的保险柜子。
如果没有索引,你须要拿着钥匙,一个个的保险柜的试过去才能找到属于你的保险柜。
但是如果有了索引,而且保险柜能够以物理分区的办法存在在对应的区域,同时你可以根据钥匙上的编号(A1003-10-17),找到保险柜所在 A1003的存放房间,找到存放室保险柜的第10排,再找到第17个位置,找到属于你的保险柜,这个定位就快很多了。
在没有索引的情形下,要想完成这个事情还是比较困难的。

php字典索引技巧_MySQL详解索引的介绍和事理分析

索引的事理

除了保险柜之外,生活中可以引出很多类似的索引例子,如字典词典的目录、图书馆的检索录、火车的座次表等。

php字典索引技巧_MySQL详解索引的介绍和事理分析
(图片来自网络侵删)

它们的事理同等:不断地缩小数据范围来筛选数据,并把随机数据变成顺序数据,方便我们更快地锁天命据。

这种索引的理解同样适用我们的数据库查询,但是数据库会有很多更繁芜的情形,除了等值查询外,还有范围查询(>、<、between、in)、模糊查询(like)、并集查询(or)、交集查询(and)等等。
这就哀求数据库选择更加繁芜和成熟的办法来应对所有问题。

根据我们上面保险柜的案例,可以对数据按照一定规则进行拆分,这样匹配的范围就降落了,但是这远远不足知够数据库繁芜的查询哀求。
于是,数据库系统的设计者从查询算法的角度进行优化。

个中最基本的查询算法是顺序查找(linear search),这种算法繁芜度为O(n),在数据量很大时就很不理想了,而且数据量越大,打算越繁芜。

但没紧要,强大的打算机科学供应了更多精良的查找算法,比如二分查找(binary search)、二叉树查找(binary tree search)等。

但是这些查找算法都哀求运用于特定的数据构造之上,如二分查找哀求被检索数据有序,而二叉树查找只能基于二叉查找树构造上操作, 数据本身的组织构造不可能完备知足各种数据构造,理论上也无法同时哀求将多列都按顺序进行组织。

因此, 在数据之外,数据库系统还掩护着知足特定查找算法的数据构造,这些数据构造以某种办法引用(指向)数据,这样就可以在这些数据构造上实现高等查找算法。
这种数据构造,便是索引。

这与上面MySQL官方对索引的定义遥相呼应了。

看下面的图:

图举例了一种索引办法。
右边是一个数据表,这边一共仿照了两列七行的数据, 字段1 的是数据记录的物理地址(实际运用中逻辑上相邻的记录在磁盘上并不一定物理相邻,这边紧张为了举例)。
为了加快 字段2 的查找,可以掩护一个左边所示的二叉查找树,每个节点分别包含索引键值和一个指向对应数据记录物理地址的指针,这样就可以利用二叉查找在O(log2n)O(log2n)的繁芜度内获取到相应数据。

这是索引的一种表现形式,但是实际的数据库系统中比较普遍是采取B+树来实现的。
B+树中的B代表平衡(balance),不是二叉(binary)。
由于B+树是从最早的平衡二叉树蜕变而来的,以是我们可以先理解下二叉查找树、平衡二叉树(AVLTree)和平衡多路查找树(B-Tree),由于B+树是由这些树逐步演进而来。

二叉查找树

二叉树具有以下性子:左子树的键值小于根的键值,右子树的键值大于根的键值。
以是左中右是依次递增的一个过程。

如下图所示便是一棵二叉查找树,

不雅观察该二叉树有有如下创造,深度为1的节点的查找次数为1,深度为2的查找次数为2,深度为n的节点的查找次数为n,因此其均匀查找次数为 (1+2+2+3+3+3+3) / 7 = 2.4次。

二叉查找树也可以是如下构造(同样知足二叉树 左 < 中 < 大的特性),同样是7,21,35,42,51,77,89 这七个数字,也可以按照下图的办法来布局:

但是这棵二叉树的查询效率就低了,均匀查找次数为(1+2+3+4+5+6+6)/7=3.8次。

因此若想二叉树的查询效率尽可能高,须要这棵二叉树是平衡的 ,从而引出新的定义:AVL树(即平衡二叉树)。

平衡二叉树(AVL Tree)

平衡二叉树(AVL树)在符合二叉查找树的条件下, 还知足任何节点的两个子树的高度最大差为1。
下面的两张图片,左边是AVL树,它的任何节点的两个子树的高度差<=1;右边的不是AVL树,其根节点的左子树高度为3,而右子树高度为1,高度差>1;

同理,在平衡二叉树进行插入或删除节点,也可能导致AVL树失落去平衡,这种失落去平衡的二叉树可以有四种状态:LL(左左)、RR(右右)、LR(旁边)、RL(右左)。

看下图示:

我们来逐一看下这几种状态。

LL(LeftLeft),即 左左。
是指插入或删除一个节点后,根节点的左孩子(Left Child)的左孩子(Left Child)还有非空节点,导致根节点的左子树比右子树高度>1,AVL树失落去平衡。

RR(RightRight),即 右右。
是指插入或删除一个节点后,根节点的右孩子(Right Child)的右孩子(Right Child)还有非空节点,导致根节点的右子树比左子树高度>1,AVL树失落去平衡。

LR(LeftRight),即 旁边。
插入或删除一个节点后,根节点的左孩子(Left Child)的右孩子(Right Child)还有非空节点,导致根节点的左子树比右子树高度>1,AVL树失落去平衡。

RL(RightLeft),即 右左。
插入或删除一个节点后,根节点的右孩子(Right Child)的左孩子(Left Child)还有非空节点,导致根节点的右子树比左子树高度>1,AVL树失落去平衡。

失落去平衡的AVL树,可以通过旋转来修复,旋转的实质是将树的节点进行调度,达到规复平衡的目的。
下面逐一来看下。

LL的旋转: LL失落去平衡的情形下,可以通过一次旋转让AVL树规复平衡。
步骤如下:

1、将根节点的左孩子作为新根节点。

2、将新根节点的右孩子作为原根节点的左孩子。

3、将原根节点作为新根节点的右孩子。

如下图所示:

RR的旋转: RR失落去平衡的情形下,旋转方法与LL旋转相反,步骤如下:

1、将根节点的右孩子作为新根节点。

2、将新根节点的左孩子作为原根节点的右孩子。

3、将原根节点作为新根节点的左孩子。

如下图所示:

LR的旋转: LR失落去平衡的情形下,须要进行两次旋转,步骤如下:

1、环绕根节点的左孩子进行RR旋转。

2、环绕根节点进行LL旋转。

如下图所示,它转了两次,末了规复成一棵AVL树:

RL的旋转: RL失落去平衡的情形下也须要进行两次旋转,旋转方法与LR旋转相反,步骤如下:

1、环绕根节点的右孩子进行LL旋转。

2、环绕根节点进行RR旋转。

如下图所示,它转了两次,末了规复成一棵AVL树:

平衡多路查找树(B-Tree)

我们知道,磁盘这种存储设备因此磁盘块(block)为基本单位的,而B-树也是基于这种存储办法设计的平衡查找树。

以是当我们从系统磁盘读取数据时,以磁盘块(block)为基本单位映射到内存中,位于同一个磁盘块中的数据会被一次性读取出来,而不是只取须要的数据。
InnoDB存储引擎中有页(Page)的观点,页是其磁盘管理的最小单位。
InnoDB存储引擎中默认每个页的大小为16KB,可通过参数innodb_page_size将页的大小设置为4K、8K、16K,我们可以在命令窗口输入以下脚本查看:

1 mysql> show variables like 'innodb_page_size';2 +------------------+-------+3 | Variable_name | Value |4 +------------------+-------+5 | innodb_page_size | 16384 |6 +------------------+-------+7 1 row in set

而系统一个磁盘块的存储空间每每没有这么大,因此InnoDB每次申请磁盘空间时都会是多少地址连续磁盘块来达到页的大小16KB。

InnoDB在把磁盘数据读入到磁盘时会以页为基本单位,在查询数据时如果一个页中的每条数据都能有助于定位数据记录的位置,

这将会减少磁盘I/O次数,提高查询效率。

B-Tree构造的数据可以让系统高效地找到数据所在的磁盘块。
为了描述B-Tree,首先定义一条记录为一个二元组[key, data] ,key为记录的键值,对应表中的主键值,data为一行记录中除主键外的数据。
对付不同的记录,key值互不相同。

一棵m阶的B-Tree有如下特性:

1. 每个节点最多有m个孩子。

2. 除了根节点和叶子节点外,其它每个节点至少有Ceil(m/2)个孩子。

3. 若根节点不是叶子节点,则至少有2个孩子

4. 所有叶子节点都在同一层,且不包含其它关键字信息

5. 每个非终端节点包含n个关键字信息(P0,P1,…Pn, k1,…kn)

6. 关键字的个数n知足:ceil(m/2)-1 <= n <= m-1

7. ki(i=1,…n)为关键字,且关键字升序排序。

8. Pi(i=1,…n)为指向子树根节点的指针。
P(i-1)指向的子树的所有节点关键字均小于ki,但都大于k(i-1)

B-Tree中的每个节点根据实际情形可以包含大量的关键字信息和分支,如下图所示为一个3阶的B-Tree:

每个节点占用一个盘块的磁盘空间,一个节点上有两个升序排序的关键字和三个指向子树根节点的指针,指针存储的是子节点所在磁盘块的地址。
两个键值数据划分成的三个范围域对应三个指针指向的子树的数据的范围域。
以根节点为例,两个键值数据为33和66,P1指针指向的子树的数据范围为小于33,P2指针指向的子树的数据范围为33~66之间,P3指针指向的子树的数据范围为大于66。

仿照查找关键字55的过程:

1、根据根节点找到磁盘块Disk1,读入内存。
第1次操作磁盘I/O。

2、比较键值55在区间(33,66),找到磁盘块Disk1的指针P2。

3、根据P2指针找到磁盘块Disk3,读入内存。
第2次操作磁盘I/O。

4、比较键值55在区间(39,62),找到磁盘块Disk3的指针P2。

5、根据P2指针找到磁盘块Disk8,读入内存。
第3次操作磁盘I/O。

6、在Disk8中的键值列表中找到关键字55。

通过上面的操作过程,创造须要3次磁盘I/O操作,和3次内存查找操作。
由于内存中的关键字是一个有序表构造, 可以利用二分法查找提高效率。
而3次磁盘I/O操作是影响全体B-Tree查找效率的决定成分。

B-Tree相对付AVLTree缩减了节点个数,使每次磁盘I/O取到内存的数据都发挥了浸染,从而提高了查询效率。

B+Tree

B+Tree是在B-Tree根本上的一种优化,使其更适宜实现外存储索引构造,InnoDB存储引擎便是用B+Tree实现其索引构造。

从上面的B-Tree构造图中可以看到每个节点中不仅包含数据的key值,还有data值。
而每一个页的存储空间是有限的,如果data数据较大时将会导致每个节点(即一个页)能存储的key的数量很小,当存储的数据量很大时同样会导致B-Tree的深度较大,增大查询时的磁盘I/O次数,进而影响查询效率。
在B+Tree中,所有数据记录节点都是按照键值大小顺序存放在同一层的叶子节点上,而非叶子节点上只存储key值信息,这样可以大大加大每个节点存储的key值数量,降落B+Tree的高度,提高查找效率。

B+Tree比较较于B-Tree的不同点:

1、非叶子节点只存储键值信息。

2、所有叶子节点之间都有一个链指针。

3、数据记录都存放在叶子节点中。

将上面的B-Tree优化,由于B+Tree的非叶子节点只存储键值信息,假设每个磁盘块能存储4个键值及指针信息,则变成B+Tree后其构造如下图所示:

常日在B+Tree上有两个头指针,一个指向根节点,另一个指向关键字最小的叶子节点,而且所有叶子节点(即数据节点)之间是一种链式环构造。
因此可以对B+Tree进行两种查找运算:一种是对付主键的范围查找和分页查找,另一种是从根节点开始,进行随机查找。

可能上面例子中只有22条数据记录,看不出B+Tree的优点,下面做一个推算:

InnoDB存储引擎中页的大小为16KB,一样平常表的主键类型为INT(占用4个字节)或BIGINT(占用8个字节),指针类型也一样平常为4或8个字节,也便是说一个页(B+Tree中的一个节点)中大概存储16KB/(8B+8B)=1K个键值(由于是估值,为方便打算,这里的K取值为〖10〗^3)。
也便是说一个深度为3的B+Tree索引可以掩护10^3 10^3 10^3 = 10亿 条记录。

实际情形中每个节点可能不能添补斥,因此在数据库中,B+Tree的高度一样平常都在2~4层。
mysql的InnoDB存储引擎在设计时是将根节点常驻内存的,也便是说查找某一键值的行记录时最多只须要1~3次磁盘I/O操作。

数据库中的B+Tree索引可以分为聚拢索引(clustered index)和赞助索引(secondary index)。
上面的B+Tree示例图在数据库中的实现即为聚拢索引,聚拢索引的B+Tree中的叶子节点存放的是整张表的行记录数据。
赞助索引与聚拢索引的差异在于赞助索引的叶子节点并不包含行记录的全部数据,而是存储相应行数据的聚拢索引键,即主键。
当通过赞助索引来查询数据时,InnoDB存储引擎会遍历赞助索引找到主键,然后再通过主键在聚拢索引中找到完全的行记录数据。

总结

根据上面,二叉查找树,红黑树等数据构造也可以用来实现索引,但是文件系统及数据库系统普遍采取B+Tree作为索引构造( 目前MySQL的MYISAM 和 INNODB 都是采取B+Tree作为索引构造 ),这是由于B+Tree索引的设计因此打算机磁盘存储构造为理论根本的。

索引以索引文件的形式存储在磁盘上,当采取B+Tree查找的时候,产生磁盘I/O花费对性能的影响比其他办法小很多( 评价一个数据构做作为索引的利害最主要的指标便是在查找过程中磁盘I/O操作次数的渐进繁芜度 )。

换句话说,索引的构造组织要只管即便减少查找过程中磁盘I/O的存取次数,而B+Tree无疑是较优的算法。

原文链接: http://www.cnblogs.com/wzh2010/p/14411428.html

如果以为本文对你有帮助,可以转发关注支持一下

标签:

相关文章