SQLITE文件结构
AndroidSQLite教程内部架构及SQLite使用办法

AndroidSQLite教程内部架构及SQLite使用办法AndroidSQLite教程:内部架构及SQLite使用办法2022-03-0609:13谢亚力IBM我要评论(0)字号:T|T本文主要讲解SQLite在Android环境中的基本使用。
Android在运行时集成了SQLite,所以每个Android应用程序都可以使用SQLite数据库。
对数熟悉SQL的开发人员来时,使用SQLite相当简单。
AD:2022大数据全球技术峰会低价抢票中SQLite介绍SQLite一个非常流行的嵌入式数据库,它支持SQL语言,并且只利用很少的内存就有很好的性能。
由于JDBC不适合手机这种内存受限设备,所以Android开发人员需要学习新的API来使用SQLite。
此外它还是开源的,任何人都可以使用它。
许多开源项目((Mozilla,PHP,Python)都使用了SQLite.SQLite由以下几个组件组成:SQL编译器、内核、后端以及附件。
SQLite通过利用虚拟机和虚拟数据库引擎(VDBE),使调试、修改和扩展SQLite的内核变得更加方便。
图1.SQLite内部架构为了创建表和索引,需要调用SQLiteDatabae的e某ecSQL()方法来执行DDL语句。
如果没有异常,这个方法没有返回值。
例如,你可以执行如下代码:1.2.db.e某ecSQL("CREATETABLEmytable(_idINTEGERPRIMARYKEYAUTOINCREMENT,titl eTE某T,valueREAL);");这条语句会创建一个名为mytable的表,表有一个列名为_id,并且是主键,这列的值是会自动增长的整数(例如,当你插入一行时,SQLite会给这列自动赋值),另外还有两列:title(字符)和value(浮点数)。
SQLite会自动为主键列创建索引。
通常情况下,第一次创建数据库时创建了表和索引。
SQLite3源程序分析_v100

SQLite3源程序分析 作者:空转 本文分析的SQLite版本为3.6.18。现在已经变成3.6.20了,但本文中所涉及的内容变化不大。读者最好能下载一个源程序,然后将本文与源程序对照阅读。这样也有利于发现本文的错误,说实话吧,我写的时候是连分析带猜的,错误肯定很多。
参考文献: 1-The Definitive Guide to SQLite . Michael Owens:比较经典的SQLite著作。我边看边翻译了其中的部分内容,但翻得不好,大家还是看原文吧。 2-SQLite文件格式分析_v102 . 空转:我写的,写得特好。现在是v102版,跟前面的版本相比增加了不少背景知识,对文件格式的介绍算是很全面了。看本文之前,应该先浏览一下此参考文献。
1. SQLite3程序分析
1.1. 主程序流程 所谓“主程序”是指SQLite所提供的命令行处理程序(CLP)。通过对它的分析可以对SQLite源程序建立整体概念,比一上来就直接分析单独API的处理过程要容易。CLP的主要程序都在shell.c中。 CLP的执行流程很简单:循环接受用户输入的SQL命令,处理SQL命令。命令的执行都是调用sqlite3_exec()函数完成,也就是采用的是“执行封装的Query”的形式[1]。 程序定义了一个功能比较强大的回叫函数来处理SQL命令执行的返回结果: static int callback(void *pArg, int nArg, char **azArg, char **azCol); 程序定义了9种回显的形式,通过一个callback_data结构来对回显参数进行配置。
1.1.1. 程序主函数 程序的main()函数在shell.c的尾部,简化后的main()函数的执行过程主要分为5步: 1. 设置回显参数 2. 取数据库文件名 3. 打开数据库 4. 循环处理SQL命令 5. 关闭数据库 如下: int main(int argc, char **argv){ struct callback_data data; //回显参数 int rc = 0; Argv0 = argv[0]; main_init(&data); //设置默认的回显形式
sqlite3数据库 复制表结构

SQLite3 是一款轻量级的数据库引擎,它的设计目标是嵌入式、小型和简单。
在实际应用中,我们经常会遇到需要复制表结构的情况,这篇文章将介绍如何使用 SQLite3 数据库复制表结构。
1. 确认版本和准备工作在进行复制表结构之前,首先要确认我们使用的是SQLite3数据库,并且已经正确安装。
如果尚未安装,需要先从冠方全球信息站下载并安装SQLite3。
安装完成后,我们要确保已经正确配置了环境变量,可以在命令行中使用sqlite3命令来打开数据库文件。
2. 打开源表和目标表我们需要打开包含源表的数据库文件,通过命令行进入到对应的目录,然后输入以下命令打开数据库文件:```sqlite3 source.db```其中,source.db 是源表所在的数据库文件名。
我们要创建一个新的数据库文件,用于存储复制后的表结构,可以使用以下命令创建目标表所在的数据库文件:```sqlite3 target.db```其中,target.db 是目标表所在的数据库文件名。
3. 获取源表结构在打开源表所在的数据库文件后,我们可以通过以下命令获取源表的结构信息:```.schema source_table```其中,source_table 是源表的表名。
这条命令会返回源表的创建语句,包括表名、字段名、字段类型、约束等信息。
4. 创建目标表在获取了源表的结构信息后,我们可以通过以下方式在目标表所在的数据库文件中创建与源表相同结构的目标表:```sqlite3 target.db``````CREATE TABLE target_table (-- 此处粘贴上一步获取的源表结构信息);```其中,target_table 是目标表的表名。
5. 复制表结构通过以上步骤,我们就能够成功复制源表的结构到目标表中。
接下来可以通过其他操作(如INSERT INTO、SELECT等)将数据从源表复制到目标表中,以完成整个复制过程。
Android学习笔记034之数据存储—SQLite数据库

Android学习笔记034之数据存储—SQLite数据库前面我们介绍了Android数据存储的两种方法:文件存储和SharedPreference存储,这一篇我们来学习一下Android存储数据的另外一种方式——SQLite数据库存储。
1、SQlite数据库简介现在的主流移动智能设备中,比如Android手机、iPhone手机,平板等都是使用SQLite 数据库作为存储复杂数据的存储引擎。
那么什么是SQLite数据库呢?SQLite是D.Richard Hipp用C语言编写的开源嵌入式数据库引擎,它支持大多数的SQL92标准,并且可以在所有主要的操作系统上运行。
SQLite由以下几个部分组成:SQL 编译器、内核、后端以及附件。
SQLite通过利用虚拟机和虚拟数据库引擎(VDBE),是调试、修改和扩展SQLite的内核变得更加方便。
所有SQL语句都被编译成易读的、可以在SQLite 虚拟机中执行的程序集。
SQlite数据库是一个轻量级的关系型数据库,不需要像其它关系型数据库一样需要安装,Android已经将SQLite数据库内置在系统中,内置的版本是3.0版本。
SQlite支持标准的SQL语法,还支持ACID(数据库事务)原则,占用资源非常少,非常适合在移动设备中使用。
袖珍型的SQLite数据库就可以支持高达2TB大小的数据库,每个数据库都是以单个文件的形式存在,这些数据都是以B-Tree的数据结构形式存储在磁盘上。
每一个数据库是一个文件,数据库中可以包含多个表,表中可以包含多个字段。
SQLite数据库支持NULL、INTEGER、REAL、TEXT和BLOB数据类型,分别代表空值、整型值、浮点值、字符串文本、二进制对象。
SQLite采用动态数据类型,当某个值插入到数据库时,SQLite将会检查它的类型,如果该类型与关联的列不匹配,SQLite则会尝试将该值转换成该列的类型,如果不能转换,则该值将作为本身的类型存储,SQLite称这为“弱类型”。
SQLite3介绍

SQLite3介绍什么是 SQLiteSQLite是⼀款轻量级的、基于⽂件的嵌⼊式数据库,实现⾃包容、零配置、⽀持事务的SQL数据库引擎。
与其他数据库管理系统不同,SQLite 的安装和运⾏⾮常简单,在⼤多数情况下,只要确保SQLite的⼆进制⽂件存在即可开始创建、连接和使⽤数据库。
第⼀个Alpha 版本诞⽣于2000年5⽉,直到今天已经成为最流⾏的嵌⼊式数据库,包括Google在内的许多公司在其桌⾯软件中亦使⽤SQLite存储⽤户数据,由此看来,其稳定性⽏庸置疑。
实际应⽤中,SQLite作为⽬前最为流⾏的开源嵌⼊式关系型数据库,在系统的架构设计中正扮演着越来越重要的⾓⾊。
和很多其它嵌⼊式NoSQL数据库(如BerkeleyDB、MemBASE等)不同的是,SQLite⽀持很多关系型数据库的基本特征,如标准SQL语法、事务、数据表和索引等,这在数据移植、程序演⽰等应⽤中有着不可替代的优势。
从官⽅⽂档中我们可以获悉到,SQLite⽀持的数据量和运⾏效率都是⾮常骄⼈的,因此在海量数据的解决⽅案中,SQLite可以作为数据预计算的桥头堡,从⽽显著减少存储在关系型数据库服务器中的数据数量,最终提⾼系统的查询效率和运⾏期效率,同时也可以显著的降低数据备份的磁盘开销。
SQLite的主要特征:1). 管理简单,甚⾄可以认为⽆需管理。
2). 操作⽅便,SQLite⽣成的数据库⽂件可以在各个平台⽆缝移植。
3). 可以⾮常⽅便的以多种形式嵌⼊到其他应⽤程序中,如静态库、动态库等。
4). 易于维护。
综上所述,SQLite的主要优势在于灵巧、快速和可靠性⾼。
SQLite的设计者们为了达到这⼀⽬标,在功能上作出了很多关键性的取舍,与此同时,也失去了⼀些对RDBMS关键性功能的⽀持,如⾼并发、细粒度访问控制(如⾏级锁)、丰富的内置函数、存储过程和复杂的SQL 语句等。
正是因为这些功能的牺牲才换来了简单,⽽简单⼜换来了⾼效性和⾼可靠性。
AndroidSQLite教程:内部架构及SQLite使用办法

AndroidSQLite教程:内部架构及SQLite使用办法Android SQLite 教程:内部架构及SQLite 使用办法2022年-03-06 09:13 谢亚力IBM 我要评论(0) 字号:T |T本文主要讲解SQLite 在Android 环境中的基本使用。
Android 在运行时集成了SQLite,所以每个Android 应用程序都可以使用SQLite 数据库。
对数熟悉SQL 的开发人员来时,使用SQLite 相当简单。
AD:2022年大数据全球技术峰会低价抢票中SQLite 介绍SQLite 一个非常流行的嵌入式数据库,它支持SQL 语言,并且只利用很少的内存就有很好的性能。
由于JDBC 不适合手机这种内存受限设备,所以Android 开发人员需要学习新的API 来使用SQLite。
此外它还是开源的,任何人都可以使用它。
许多开源项目((Mozilla, PHP, Python)都使用了SQLite.SQLite 由以下几个组件组成:SQL 编译器、内核、后端以及附件。
SQLite 通过利用虚拟机和虚拟数据库引擎(VDBE),使调试、修改和扩展SQLite 的内核变得更加方便。
图 1. SQLite 内部架构SQLite 基本上符合SQL-92 标准,和其他的主要SQL 数据库没什么区别。
它的优点就是高效,Android 运行时环境包含了完整的SQLite。
SQLite 和其他数据库最大的不同就是对数据类型的支持,创建一个表时,可以在CREATE TABLE 语句中指定某列的数据类型,但是你可以把任何数据类型放入任何列中。
当某个值插入数据库时,SQLite 将检查它的类型。
如果该类型与关联的列不匹配,则SQLite 会尝试将该值转换成该列的类型。
如果不能转换,则该值将作为其本身具有的类型存储。
比如可以把一个字符串(String)放入__ 列。
SQLite 称这为“弱类型”(manifest typing.)。
sqlite3用法
sqlite3用法SQLite3是一个轻量级的嵌入式数据库,它不需要独立的数据库服务器进程,而是将整个数据库放在一个单一的文件中。
SQLite3提供了一系列的命令行工具,用于管理SQLite3数据库。
以下是一些常用的SQLite3命令:1. 打开数据库文件:sqlite3 filename.db2. 查看数据库结构:.schema3. 查看表结构:.schema tablename4. 查询表数据:SELECT * FROM tablename;5. 插入数据:INSERT INTO tablename (col1, col2, ...) VALUES (val1, val2, ...);6. 更新数据:UPDATE tablename SET col1=val1, col2=val2, ... WHERE condition;7. 删除数据:DELETE FROM tablename WHERE condition;8. 查看表中的所有列名:PRAGMA table_info(tablename);9. 导出数据:.output filename.csv 或者 SELECT * FROM tablename INTO OUTFILE 'filename.csv' FIELDS TERMINATED BY ',' 10. 导入数据:.import filename.csv tablenameSQLite3还提供了一些高级功能,例如创建视图、索引、触发器等,可以通过SQLite3的语法来实现。
总之,SQLite3是一个小巧、方便的数据库,适用于小型应用程序的数据存储需求。
对于开发者来说,掌握SQLite3的用法是非常重要的。
SQLite学习
SQLite 是一个开源的嵌入式关系数据库,实现自包容、零配置、支持事务的SQL数据库引擎。
其特点是高度便携、使用方便、结构紧凑、高效、可靠。
与其他数据库管理系统不同,SQLite 的安装和运行非常简单,在大多数情况下- 只要确保SQLite的二进制文件存在即可开始创建、连接和使用数据库。
如果您正在寻找一个嵌入式数据库项目或解决方案,SQLite是绝对值得考虑。
1. 安装SQLite on Windows∙进入SQL 下载页面:/download.html∙下载Windows 下的预编译二进制文件包:∙sqlite-shell-win32-x86-<build#>.zip∙sqlite-dll-win32-x86-<build#>.zip注意: <build#> 是sqlite 的编译版本号∙将zip 文件解压到你的磁盘,并将解压后的目录添加到系统的PATH 变量中,以方便在命令行中执行sqlite 命令。
∙可选: 如果你计划发布基于sqlite 数据库的应用程序,你还需要下载源码以便编译和利用其API∙sqlite-amalgamation-<build#>.zipSQLite on Linux在多个Linux 发行版提供了方便的命令来获取SQLite:/* For Debian or Ubuntu /*$ sudo apt-get install sqlite3 sqlite3-dev/* For RedHat, CentOS, or Fedora/*$ yum install SQLite3 sqlite3-devSQLite on Mac OS X如果你正在使用Mac OS 雪豹或者更新版本的系统,那么系统上已经装有SQLite 了。
2. 创建首个SQLite 数据库现在你已经安装了SQLite 数据库,接下来我们创建首个数据库。
在命令行窗口中输入如下命令来创建一个名为test.db 的数据库。
sqlite btree 索引 -回复
sqlite btree 索引-回复[SQLite B树索引]B树(B-tree)是一种自平衡的树数据结构,常用于数据库和文件系统中的索引结构。
SQLite作为一种轻量级的嵌入式数据库管理系统,也使用了B树索引来提高查询效率和数据存储优化。
本文将以SQLite中B树索引为主题,一步一步回答有关B树索引的相关问题。
1. 什么是B树索引?B树索引是一种将数据按照特定顺序组织的数据结构,可以加速在数据库中的查找和排序操作。
B树索引使用B树的结构,可以在特定时间复杂度内快速定位和查询数据。
2. B树索引有什么特点?B树索引的几个特点如下:- 平衡性:B树索引始终保持平衡,即每个节点的左右子树的高度差不超过1。
- 多节点:B树索引每个节点可以存储多个键值和对应的数据指针。
- 顺序存储:B树索引将数据按照键值的顺序进行存储,便于范围查询。
- 磁盘IO优化:B树索引通过多层次的节点结构,减少磁盘IO次数,提高查询效率。
3. SQLite中是如何实现B树索引的?SQLite中使用B树索引来优化查询操作。
它将每个表的每个列都存储在一个B树中,这个B树被称为表的索引。
在一个B树中,每个节点不只包含键值和数据指针,还可能包含其他信息,如子节点指针和计数器等。
4. SQLite中的B树索引是如何存储的?SQLite使用虚拟页(Virtual Page)的概念来存储和管理B树索引。
虚拟页是一个固定大小的块(通常为4KB),可以包含一个或多个逻辑上连续的数据库页。
SQLite会根据需要将一些连续的实际数据库页映射到一个虚拟页中,这样可以减少磁盘IO。
5. SQLite中B树索引的结构是怎样的?SQLite中的B树索引由多个页面组成,根据B树的特性,一般包括根页面、中间页面和叶页面。
其中,根页面是B树的起点,中间页面用于连接叶页面和根页面,叶页面存储实际的键值和数据。
6. B树索引在SQLite中是如何工作的?当我们执行一个查询操作时,SQLite会根据需要遍历B树索引,根据键值的顺序进行查找。
Android中SQLite应用详解
SQLite是D。
Richard Hipp用C语言编写的开源嵌入式数据库引擎。
它支持大多数的SQL92标准,并且可以在所有主要的操作系统上运行。
SQLite由以下几个部分组成:SQL编译器、内核、后端以及附件。
SQLite通过利用虚拟机和虚拟数据库引擎(VDBE),是调试、修改和扩展SQLite的内核变得更加方便。
所有SQL语句都被编译成易读的、可以在SQLite虚拟机中执行的程序集。
SQLite的整体结构图如下:值得一提的是,袖珍型的SQLite竟然可以支持高达2TB大小的数据库,每个数据库都是以单个文件的形式存在,这些数据都是以B—Tree的数据结构形式存储在磁盘上.在事务处理方面,SQLite通过数据库级上的独占性和共享锁来实现独立事务处理。
这意味着多个进程可以在同一时间从同一数据库读取数据,但只有一个可以写入数据。
在某个进程或线程想数据库执行写操作之前,必须获得独占锁。
在获得独占锁之后,其他的读或写操作将不会再发生。
SQLite采用动态数据类型,当某个值插入到数据库时,SQLite将会检查它的类型,如果该类型与关联的列不匹配,SQLite则会尝试将该值转换成该列的类型,如果不能转换,则该值将作为本身的类型存储,SQLite称这为“弱类型”。
但有一个特例,如果是INTEGER PRIMARY KEY,则其他类型不会被转换,会报一个“datatype missmatch”的错误。
概括来讲,SQLite支持NULL、INTEGER、REAL、TEXT和BLOB数据类型,分别代表空值、整型值、浮点值、字符串文本、二进制对象。
下面,我们就来亲自操作一下SQLite数据库。
在操作之前,朋友们要先下载SQLite数据库,官方的下载页面是http:///download。
html,我是在Windows下试验,所以我选择了Precompiled Binaries For Windows下面的sqlite-shell—win32—x86和sqlite-analyzer-win32-x86的zip包,前者是SQLite数据库引擎,后者是SQLite数据库分析器,主要用于分析数据库的状态等信息,大家也可以根据自己的情况去下载。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
从逻辑上来说,一个SQLite数据库文件由多个多重Btree构成。每个Btree存储一个表的数据或一个表的索引,索引采用B-tree,而表数据采用B+tree,每个Btree占用至少一个完整的页,每个页是Btree的一个结点。每个表或索引的第1个页称为根页,所有表或索引的根页编号都存储在系统表sqlite_master中,表sqlite_master的根页为page1。注:sqlite_master是一个系统表,保存了数据库的schema信息,详参“关于sqlite_master表”一节。
数据库中第一个页(page1)永远是Btree页。Page1的前100个字节是一个对数据库文件进行描述的“文件头”。它包括数据库的版本、格式的版本、页大小、编码等所有创建数据库时设置的永久性参数。关于这个特殊文件头的文档在btreeInt.h中,具体格式如下:
头100:偏移量大小说明016头字符串,如果不改源程序,此字符串永远是"SQLiteformat3"。162页大小(以字节为单位)。181文件格式版本(写)。对于SQLite的当前版本,此值为1。如果该值大于1,表示文件为只读。SQLite将来版本对此域的规定可能改变。191文件格式版本(读)。对于SQLite的当前版本,此值为1。如果该值大于1,SQLite认为文件格式错,拒绝打开此文件。SQLite将来版本对此域的规定可能改变。201每页尾部保留空间的大小。(留作它用,默认为0。)211Btree内部页中一个单元最多能够使用的空间。255意味着100%,默认值为0x40,即64(25%),这保证了一个结点(页)至少有4个单元。221Btree内部页中一个单元使用空间的最小值。默认值为0x20,即32(12.5%)。231Btree叶子页中一个单元使用空间的最小值。默认值为0x20,即32(12.5%)。注:SQLite的当前版本规定21~23的3个字节值只能是0X402020。原来这3个字节值是可变的,从3.6.0版开始被固定下来了。244文件修改计数,通常被事务使用,由事务增加其值。SQLite用此域的值验证内存缓冲区中数据的有效性。284未使用。324空闲页链表首指针。参“空闲页”一节。364文件内空闲页的数量。406015个4字节的元数据变量。
1.页头2.单元指针数组3.未分配空间4.单元内容区Btree页内部以单元(cell)为单位来组织数据,一个单元包含一个(或部分,当使用溢出页时)payload(也称为Btree记录)。由于各类数据大小各不相同,每个单元的大小也就是可变的,所以Btree页内部的空间需要进行动态分配(程序内部动态分配,不是动态申请空间),单元是Btree页内部进行空间分配和回收的基本单位。页内所有单元的内容集中在页的底部,称为“单元内容区”,由下向上增长。
就不用管各标志位的含义了,如果是B+tree的叶子页,该字节值为0X0D,如果是B+tree的内部页,该字节值为0X05,如果是B-tree的叶子页,该字节值为0X0A,如果是B-tree的内部页,该字节值为0X02。由此可见:intkey标志倒是可以作为判断B+tree树和B-tree的标志(置1为B+tree树),程序中实际也是这样应用的。最右儿子的页号:如果本Btree页是叶子页,则无此域,页头长为8个字节。如果本Btree页为内部页,则有此域,页头长为12个字节。页头的格式如下:偏移量大小说明01页类型标志。1:intkey,2:zerodata,4:leafdata,8:leaf。12第1个自由块的偏移量。32本页的单元数。52单元内容区的起始地址。71碎片的字节数。84最右儿子的页号(thePtr(n)value)。仅内部页有此域。
0.1.1B+tree叶子页的单元格式单元是变长的字节串。一个单元包含一个(或部分,当使用溢出页时)payload。B+tree叶子页单元的结构如下:大小说明var(1–9)Payload大小,以字节为单位。var(1–9)数据库记录的Rowid值。*Payload内容,存储数据库中某个表一条记录的数据。4溢出页链表中第1个溢出页的页号。如果没有溢出页,无此域。结合实例来说明吧。当前的单元内容区中只有一个单元,从0X0399开始,内容如下图所示:0X65:Payload数据的字节数。可以看出Payload数据是从0717~2029。0X01:foods(table对象)在sqlite_master表中对应记录的rowid,值为0X01。Payload的格式如下图所示:
每个payload由两部分组成。第1部分是记录头,由N+1个可变长整数组成,N为记录中的字段数。第1个可变长整数(header-size)的值为记录头的字节数。跟着的N个可变长整数与记录的各字段一一对应,表示各字段的数据类型和宽度。用可变长整数表示各字段类型和宽度的规定如下表所示:类型值含义数据宽度(字节数)0NULL0Nin1..4有符号整数N5有符号整数66有符号整数87IEEE符点数88-11未使用N/AN>12的偶数BLOB(N-12)/2N>13的奇数TEXT(N-13)/2header-size的值包括header-size本身的字节和Type1~TypeN的字节。Data1~DataN为各字段数据,与Type1~TypeN一一对应,类型和宽度由Type1~TypeN指定。本例的payload数据为:0X07:记录头包括7个字节。0X17:字段1。TEXT,长度为:(23-13)/2=5。值为:table。0X17:字段2。TEXT,长度为:(23-13)/2=5。值为:foods。0X17:字段3。TEXT,长度为:(23-13)/2=5。值为:foods。0X01:字段4。整数,长度为1。值为:0X02。表示本表B+tree的根页编号为2。0X8129:字段5。TEXT。0X8129为可变长整数,转换为定长为0XA9=169。可知字段长度为:(169-13)/2=78=0X4E。对应数据为下图中蓝色部分。
0.2B+tree内部页格式介绍
Page2仍然是表foods的根页,但已经变成了内部页,格式有较大的变化。对于数据库表,从SQLite3开始采用了B+tree,在此,先对B+tree的结构做一个简单介绍。B+tree与B-tree的主要区别在于,B-tree的所有页上都包含数据,而B+tree的数据只存在于
叶子页上,内部页只存储导航信息。B+tree所有的叶子页都在同一层上,并按关键字排序,所有的关键字必须唯一,其逻辑结构举例如下图所示:
B+tree中根页(rootpage)和内部页(internalpages)都是用来导航的,这些页的指针域都是指向下级页的指针,数据域仅仅包含关键字。所有的数据库记录都存储在叶子页(leafpages)内。在叶节点一级,页和页内的单元都是按照关键字的顺序排列的,所以B+tree可以沿水平方向遍历,时间复杂度为O(1)。我们将根页和内部页统称为内部页,它们的结构是相同的,其逻辑结构如下:----------------------------------------------------------------|Ptr(0)|Key(0)|Ptr(1)|Key(1)|...|Key(N-1)|Ptr(N)|----------------------------------------------------------------内部页包含N个关键值(Key(0)~Key(N-1))和N+1个子页指针(Ptr(0)~Ptr(N)),其值为子页的页号。其中,Ptr(N)存储在页头中偏移为8的地方(4字节整数,只有内部页的页头有此域,参“Btree页格式介绍”一节)。其他的每对子页指针和关键值(Ptr(i)和Key(i))组成1个单元,共N个单元。Ptr(i)所指向子树中关键字的最大值<=Key(i),Ptr(N)所指向子树中关键字的值都>Key(N-1)。
0.3B+tree内部页格式分析现在对foodsB+tree仅有的内部页进行分析。文件第2页页头的内容如下:(图中深蓝色部分)
前文对页头格式已经有比较详细的介绍,这里不再赘述。直接对内容进行说明:0X05:说明该页为B+tree的内部页。0X0000:第1个自由块的偏移量。此处为0,表示本页没自由块。0X0002:本页有2个单元。0X03F6:单元内容区的起始位置。0X00:碎片的字节数,此处为0。0X00000005:最右儿子的页号,即Ptr(N)。由于本页有2个单元,所以此处即Ptr(2)。其值为0X05,即Ptr(2)指向第5页。第5页是表数据的最后一页,也是当前文件的最后一页。
单元指针数组在页头之后,有2个指针,分别为0X03FB和0X03F6。注意:这两个指针后面还有一些乱七八糟内容,我也曾为此迷惑过。这些不是指针,而是属于“未分配空间”的一部分。因为此页在还没有成为内部页(还是叶子页)时,曾经插入过不少记录,有过不少指针。现在成为内部页了,只使用两个指针,但以前使用过的空间也没必要清零,再次使用时自然会覆盖。提示:此页尾部的内容区也存在这个情况,不再单独解释。
下面来看单元内容区的数据,内容如下:(图中深蓝色部分)由于单元内容区中各单元是反向增长的,所以两个单元的数据分别为:0X00000003,0X2C0X00000004,0X56每个单元包括两部分内容:一个4字节的页号,指向相应的儿子,即Ptr(i)。此处分别指向第3页和第4页。一个可变长整数,即Key(i)。0X2C表示最左儿子(文件第3页)中关键字值都<=0X2C。0X56表示第2个儿子(文件第4页)中关键字都>0X2C,都<=0X56。注意:关键字值使用可变长整数,我们插入的记录少,在此都只有1个字节,所以看不出来。前文刚介绍过,最右儿子的页号存储在页头中,值为0X00000005,说明第5页中关键字值都>0X56。重画前文B+tree的逻辑结构图如下所示:
0.4叶子页格式分析其实在上一章中分析page1和page2时,这两个页都是叶子页。这里再次对叶子页的格式进行分析,主要是为了验证前一节对内部页的分析结果,所以,咱就别嫌麻烦了。文件第4页页头的内容如下:(图中深蓝色部分)
之所以选择第4页,是因为该页为中间叶子,其记录的关键值应该在Key(0)和Key(1)之间。从上图可以看出,本页有0X2A=42个单元。第1个单元的入口地址为0X03E7,最后一个单元的入口地址为0X006F。0X03E7单元的内容为: