00 – 背景知识
- B-Tree & B+Tree
http://en.wikipedia.org/wiki/B%2B_tree
http://en.wikipedia.org/wiki/B-tree
- 折半查找(Binary Search)
http://en.wikipedia.org/wiki/Binary_search_algorithm
- 数据库的性能问题
A. 磁盘IO性能非常低,严重的影响数据库系统的性能。
B. 磁盘顺序读写比随机读写的性能高很多。
- 数据的基本存储结构
A. 磁盘空间被划分为许多大小相同的块(Block)或者页(Page).
B. 一个表的这些数据块以链表的方式串联在一起。
C. 数据是以行(Row)为单位一行一行的存放在磁盘上的块中,如图所示.
D. 在访问数据时,一次从磁盘中读出或者写入至少一个完整的Block。
Fig. 1
01 – 数据基本操作的实现
基本操作包括:INSERT、UPDATE、DELETE、SELECT。
- SELECT
A. 定位数据
B. 读出数据所在的块,对数据加工
C. 返回数据给用户
- UPDATE、DELETE
A. 定位数据
B. 读出数据所在的块,修改数据
C. 写回磁盘
- INSERT
A. 定位数据要插入的页(如果数据需要排序)
B. 读出要插入的数据页,插入数据.
C. 写回磁盘
如何定位数据?
- 表扫描(Table Scan)
A. 从磁盘中依次读出所有的数据块,一行一行的进行数据匹配。
B. 时间复杂度 是O(n), 如果所有的数据占用了100个块。尽管只查询一行数据,
也需要读出所有100个块的数据。
C. 需要大量的磁盘IO操作,极大的影响了数据定位的性能。
因为数据定位操作是所有数据操作必须的操作,数据定位操作的效率会直接影响所有的数据操作的效率。
因此我们开始思考,如何来减少磁盘的IO?
- 减少磁盘IO
A. 减少数据占用的磁盘空间
压缩算法、优化数据存储结构
B. 减少访问数据的总量
读出或写入的数据中,有一部分是数据操作所必须的,这部分称作
有效数据。剩余的
部分则不是数据操作必须的数据,称为无效数据。例如,查询姓名是‘张三’的记录。
那么这条记录是有效记录,其他记录则是无效记录。我们要努力减少无效数据的访问。
02 – 索引的产生
- 键(Key)
首先,我们发现在多数情况下,定位操作并不需要匹配整行数据。而是很规律的只匹配某一个
或几个列的值。 例如,图中第1列就可以用来确定一条记录。这些用来确定一条数据的列,统
称为键(Key)
.
Fig. 2
- Dense Index
根据减少无效数据访问的原则,我们将键的值拿过来存放到独立的块中。并且为每一个键值添
加一个指针, 指向原来的数据块。如图所示,
Fig. 3
这就是‘索引’的祖先Dense Index
. 当进行定位操作时,不再进行表扫描。而是进行
索引扫描(Index Scan)
,依次读出所有的索引块,进行键值的匹配。当找到匹配的键值后,
根据该行的指针直接读取对应的数据块,进行操作。假设一个块中能存储100行数据,
10,000,000行的数据需要100,000个块的存储空间。假设键值列(+指针)占用一行数据
1/10的空间。那么大约需要10,000个块来存储Dense索引。因此我们用大约1/10的额外存储
空间换来了大约全表扫描10倍的定位效率。
03 – 索引的进化
在实际的应用中,这样的定位效率仍然不能满足需求。很多人可能已经想到了,通过排序和查找
算法来减少IO的访问。
因此我们开始尝试对Dense Index进行排序存储,并且期望利用排序查
找算法来减少磁盘IO。
- 折半块查找
A. 对Dense Index排序
B. 需要一个数组按顺序存储索引块地址。以块为单位,不存储所有的行的地址。
C. 这个索引块地址数组,也要存储到磁盘上。将其单独存放在一个块链中,如下图所示。
D. 折半查找的时间复杂度是O(log 2
(N
))。在上面的列子中,dense索引总共有10,000个块。假设1个块
能存储2000个指针,需要5个块来存储这个数组。通过折半块查找,我们最多只需要读取
5(数组块)+ 14(索引块
log 2
(10000))+1(数据块)=20个块。
Fig. 4
- Sparse Index
实现基于块的折半查找时发现,读出每个块后只需要和第一行的键值匹配,就可以决定下一个块
的位置(方向)。 因此有效数据是每个块(最后一个块除外)的第一行的数据。还是根据减少无
效数据IO的原则,将每一个块的第一行的数据单独拿出来,和索引数组的地址放到一起。这样就
可以直接在这个数组上进行折半查找了。如下图所示,这个数组就进化成了Sparse Index
。
Fig. 5
因为Sparse Index和Dense Index的存储结构是相同的,所以占用的空间也相同。大约需
要10个块来存储10000个Dense Index块的地址和首行键值。通过Sparse索引,仅需要读
取10(Sparse块)+1(Dense块)+1(数据块)=12个块.
- 多层Sparse Index
因为Sparse Index本身是有序的,所以可以为Sparse Index再建sparse Index。通过
这个方法,一层一层的建立 Sparse Indexes,直到最上层的Sparse Index只占用一个块
为止,如下图所示.
Fig. 6
A. 这个最上层的Sparse Index称作整个索引树的根(root).
B. 每次进行定位操作时,都从根开始查找。
C. 每层索引只需要读出一个块。
D. 最底层的Dense Index或数据称作叶子(leaf).
E. 每次查找都必须要搜索到叶子节点,才能定位到数据。
F. 索引的层数称作索引树的高度(height).
G. 索引的IO性能和索引树的高度密切相关。索引树越高,磁盘IO越多。
在我们的例子中的Sparse Index,只有10个块,因此我们只需要再建立一个Sparse Index.
通过两层Sparse Index和一层Dense Index查找时,只需读取1+1+1+1=4个块。
- Dense Index和Sparse Index的区别
A. Dense Index包含所有数据的键值,但是Sparse Index仅包含部分键值。
Sparse Index占用更少的磁盘空间。
B. Dense Index指向的数据可以是无序的,但是Sparse Index的数据必须是有序的。
C. Sparse Index 可以用来做索引的索引,但是Dense Index不可以。
D. 在数据是有序的时候,Sparse Index更有效。因此Dense Index仅用于无序的数据。
E. 索引扫描(Index Scan)实际上是对Dense Index层进行遍历。
- 簇索引(Clustered Index)和辅助索引(Secondary Index)
如果数据本身是基于某个Key来排序的,那么可以直接在数据上建立sparse索引,
而不需要建立一个dense索引层(可以认为数据就是dense索引层)。 如下图所示:
Fig. 7
这个索引就是我们常说的“Clustered Index
”,而用来排序数据的键叫做主键Primary Key
.
A. 一个表只能有一个Clustered Index,因为数据只能根据一个键排序.
B. 用其他的键来建立索引树时,必须要先建立一个dense索引层,在dense索引层上对此键的值
进行排序。这样的索引树称作Secondary Index
.
C. 一个表上可以有多个Secondary Index.
D. 对簇索引进行遍历,实际上就是对数据进行遍历。因此簇索引的遍历效率比辅组索引低。
如SELECT count(*) 操作,使用辅组索引遍历的效率更高。
- 范围搜索(Range Search)
由于键值是有序的,因此可以进行
范围查找。只需要将数据块、Dense Index块分别以双向链表
的方式进行连接, 就可以
实现高效的范围查找。如下图所示:
Fig. 8
范围查找的过程:
A. 选择一个合适的边界值,定位该值数据所在的块
B. 然后选择合适的方向,在数据块(或Dense Index块)链中进行遍历。
C. 直到数据不满足另一个边界值,结束范围查找。
是不是看着这个索引树很眼熟?换个角度看看这个图吧!
Fig. 9
这分明就是传说中的B+Tree.
- 索引上的操作
A. 插入键值
B. 删除键值
C. 分裂一个节点
D. 合并两个节点
这些操作在教科书上都有介绍,这里就不介绍了。
先写到这吧,实在写不动了,想明白容易,写明白就难了。下一篇里,打算谈谈标准B+Tree的几个问题,以及在
实现过程中,B+Tree的一些变形。
很多知识来自于下面这两本书。
“Database Systems: The Complete Book (2nd Edition)
”
“Transaction Processing: Concepts and Techniques”
推荐关联性文章:
由浅入深理解索引的实现(2)
分享到:
相关推荐
### 数据结构与算法大全:由浅入深介绍数据结构的基础知识 #### 一、数据结构的概念 **数据结构**是在整个计算机科学与技术领域中广泛使用的术语,它用来描述数据的内部构成及其组织形式。数据结构包括两个方面:*...
1. **数据库简介**:数据库是存储和管理数据的系统,而MySQL是一个开源、免费的SQL数据库,支持多种操作系统。它提供了数据的安全性、可靠性和高效性能。 2. **安装**:安装MySQL涉及下载适合操作系统的二进制包,...
总结,实现相似图片搜索涉及多个步骤,包括特征提取、向量表示、距离计算和索引构建。Java提供了丰富的库(如TensorFlow和Lucene)来支持这些操作,使得开发者能够在Java环境中实现高效且准确的相似图片搜索系统。...
由浅入深,适合新手"的课程中,你将逐步学习到这些内容,并通过实践加深理解。无论你是Web开发者、数据分析师还是系统管理员,掌握MySQL都将为你的职业生涯带来极大的帮助。通过不断学习和实践,你将能够熟练地运用...
"大量JAVA例子(各种各样例子,由浅入深)"这个压缩包文件显然包含了多个用于学习和理解Java编程的实例,旨在帮助初学者逐步掌握Java语言的核心概念和高级特性。 首先,让我们从基础开始。在Java中,基础概念包括...
本教程《C#由浅入深》旨在为初学者提供一个全面理解C#语言的基础,同时也适合有一定经验的开发者作为参考。 一、C#基础语法 C#的基本语法结构与C++和Java类似,它包含变量声明、数据类型(如int、string、bool等)...
1. **数组**:是最基础的数据结构,它将元素存储在连续的内存位置中,通过索引访问。数组的优点是访问速度快,但插入和删除操作可能需要移动大量元素。 2. **链表**:与数组不同,链表的元素在内存中不一定是连续的...
1. 线性数据结构:这是最基本的数据结构,如数组、链表、栈和队列。数组是一种静态的数据结构,通过索引访问元素,提供快速的随机访问。链表则由节点构成,每个节点包含数据和指向下一个节点的引用,适合动态变化的...
1. **索引过程**:Lucene的索引过程主要包括文档分析、字段处理、倒排索引构建等步骤。文档分析是将原始文本分解为关键词,通常使用Analyzer进行分词;字段处理则涉及对不同字段的设置,如是否存储、是否可被索引等...
例如,`append()`方法用于在列表末尾添加元素,`extend()`用于合并两个列表,`insert()`在指定位置插入元素,`remove()`删除第一个匹配的元素,`pop()`删除并返回指定索引的元素,`clear()`清空列表,`index()`查找...
首先,我们从需求分析开始,学生信息管理系统需要实现四大功能:添加学生信息、修改学生信息、查询学生信息和删除学生信息。系统中的每个学生信息包括学号、姓名、年龄、性别和地址五个字段。为了存储这些信息,我们...
内容概要:本文档详述了MySQL数据库课程设计中的学员信息管理系统设计与实现。主要内容包括:1. 数据库设计基础,介绍基本概念、术语及正规化技术;2. 数据库表设计,提供具体的SQL语句和示例数据来构建学员信息表、...
本教程是针对初学者设计的,通过一系列PPT课件,由浅入深地介绍了SQL Server 2005的基础知识和核心功能。 ### 1. SQL Server 2005概述 SQL Server 2005基于.NET Framework 2.0,提供了强大的数据管理和分析能力,...
通过实践,我们可以更直观地理解数据库操作,例如创建和修改表、设置排序和索引、进行数据统计以及管理多个工作区。实验通常与理论课紧密结合,逐步提升难度,让学生在实践中深化理解。初次接触时,老师会提供详细的...
它们可以帮助实现关键词提取、索引创建和文档分类等功能。在Java中,Lucene和Solr等搜索库就内置了强大的分词过滤器。 ### 7. 触发资源访问事件的过滤器(Filters that Trigger Resource Access Events) 这类过滤...
本书不仅对数据结构进行了由浅入深的阐述,还通过C语言的实现让读者能够亲自动手,将理论知识转化为实际操作,从而达到深刻理解和灵活运用的目的。 在理论方面,这本书首先介绍了数组,它是最基本、最简单也是最...
理解设备状态、交换链、顶点缓冲和索引缓冲的概念。 3. **顶点和像素着色器**:DirectX 9引入了高级着色模型,允许开发者编写自定义的顶点和像素着色器程序,以实现复杂的光照、纹理映射和视觉效果。 4. **纹理和...