SQLite数据库文件格式(十五)

 返回:SQLite—系列文章目录   

上一篇:SQLite 4.9的虚拟表机制(十四)

下一篇:SQLite超详细的编译时选项(十六)

► 目录

本文档描述和定义磁盘上的数据库文件 自 SQLite 以来所有版本使用的格式 版本 3.0.0 (2004-06-18).

1. 数据库文件

SQLite数据库的完整状态通常是 包含在磁盘上的单个文件中,称为“主数据库文件”。

在事务期间,SQLite存储其他信息 在称为“回滚日志”的第二个文件中,或者如果 SQLite 处于 WAL 模式,则为预写日志文件。

1.1. 热门期刊

如果应用程序或 主机在事务完成之前崩溃,然后回滚 日志或预写日志包含所需的信息 将主数据库文件还原到一致状态。回滚时 日志或预写日志包含恢复所需的信息 数据库的状态,它们被称为“热日志”或“热WAL文件”。 热日志和WAL文件只是错误恢复过程中的一个因素 场景等并不常见,但它们是 SQLite 状态的一部分 数据库等不能忽视。本文档定义了格式 回滚日志和预写日志文件,但重点是 在主数据库文件上。

1.2. 页面

主数据库文件由一个或多个页面组成。的大小 Page 是介于 512 和 65536 之间的 2 次幂(含)。内所有页面 相同的数据库具有相同的大小。数据库文件的页面大小 由位于 从数据库文件开头开始的 16 个字节。

页码以 1 开头。最大页码为 4294967294(2,32-2)。最小尺寸 SQLite 数据库是一个 512 字节的页面。 最大大小的数据库将是 4294967294 页,每 65536 字节 页面或 281,474,976,579,584 字节(约 281 TB)。通常 SQLite 会 达到底层文件系统或磁盘的最大文件大小限制 硬件早在它达到自己的内部大小限制之前。

在通常的使用中,SQLite数据库的大小往往从几千字节不等 到几千兆字节,尽管已知存在 TB 大小的 SQLite 数据库 在生产中。

在任何时间点,主数据库中的每个页面都有一个 使用以下方法之一:

  • 锁定字节页面
  • 自由列表页面
    • 自由列表主干页面
    • 自由列表叶页面
  • b 树页面
    • 表格b-tree内页
    • 表 b 树叶页
    • 索引 b 树内页
    • 索引 b 树叶页
  • 有效负载溢出页面
  • 指针映射页

对主数据库文件的所有读取和写入都从一页开始 boundary 和 all writes 的大小为整数页数。读 通常也是整数页的大小,但有一个例外 当数据库首次打开时,前 100 个字节的 数据库文件(数据库文件头)作为子页面大小单位读取。

在修改数据库的任何信息页面之前, 该页面的原始未修改内容将写入 回滚日志。如果事务中断并且需要 回滚,然后可以使用回滚日志来恢复 数据库恢复到其原始状态。Freelist 叶子页没有 需要在回滚时还原的信息,因此它们 在修改之前没有写入期刊,以便 减少磁盘 I/O。

1.3. 数据库头

数据库文件的前 100 个字节构成数据库文件 页眉。数据库文件头分为多个字段,如下所示 下表。数据库文件头中的所有多字节字段都是 首先使用最高有效字节 (big-endian) 存储。

数据库头格式

偏移大小说明
016标头字符串:“SQLite 格式 3\000”
162数据库页面大小(以字节为单位)。必须是 2 之间的 512 次幂 和 32768(含 32768),或值 1 表示页面大小为 65536。
181文件格式写入版本。1 用于遗产;2 表示 WAL。
191文件格式读取版本。1 用于遗产;2 表示 WAL。
201每页末尾未使用的“保留”空间的字节数。通常为 0。
211最大嵌入有效载荷分数。必须年满 64 岁。
221最小嵌入式有效载荷分数。必须年满 32 岁。
231叶片有效载荷分数。必须年满 32 岁。
244文件更改计数器。
284数据库文件的大小(以页为单位)。“in-header 数据库大小”。
324第一个自由列表主干页面的页码。
364免费列表页面总数。
404架构 cookie。
444架构格式编号。支持的架构格式为 1、2、3 和 4。
484默认页面缓存大小。
524自动抽真空或 增量真空模式,否则为零。
564数据库文本编码。值为 1 表示 UTF-8。值为 2 表示 UTF-16le。值 3 表示 UTF-16be。
604由user_version编译指示读取和设置的“用户版本”。
644增量真空模式为 True(非零)。否则为 false(零)。
684PRAGMA 设置的“应用程序 ID”application_id。
7220保留用于扩展。必须为零。
924version-valid-for 编号。
964SQLITE_VERSION_NUMBER

1.3.1. 魔术头字符串

每个有效的 SQLite 数据库文件都以下列 16 个字节开头 (十六进制):53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00。此字节序列 对应于 UTF-8 字符串“SQLite format 3”,包括 nul 末尾的终结者角色。

1.3.2. 页面大小

从偏移量 16 开始的双字节值决定了 数据库。对于 SQLite 版本 3.7.0.1 (2010-08-04) 在更早的时候,这个值是 解释为大端整数,并且必须是 2 之间的幂 512 和 32768(含)。从 SQLite 版本 3.7.1 (2010-08-23) 开始,一个页面 支持 65536 字节的大小。值 65536 不适合 双字节整数,因此要指定 65536 字节的页面大小,值 偏移量为 16 0x00 0x01。 此值可以解释为大端 1 并被认为是一个表示 65536 页面大小的幻数。 或者可以将两字节字段视为一个小字节数,然后说 它表示页面大小除以 256。这两个 对 page-size 字段的解释是等效的。

1.3.3. 文件格式版本号

偏移的文件格式写入版本和文件格式读取版本 18 和 19 旨在允许增强文件格式 在 SQLite 的未来版本中。在当前版本的 SQLite 中,两者都 对于回滚日记模式,这些值为 1,对于 WAL 日记模式,这些值为 2。如果 SQLite 的版本编码为当前 文件格式规范遇到一个数据库文件,其中读取 version 为 1 或 2,但写入版本大于 2,则数据库 文件必须被视为只读。如果具有读取版本的数据库文件 如果遇到大于 2,则无法读取或写入该数据库。

1.3.4. 每页保留字节数

SQLite能够在 每个页面的末尾,供扩展使用。这些额外的字节是 例如,SQLite 加密扩展用于存储随机数 和/或与每个页面关联的加密校验和。这 偏移量 20 处的 1 字节整数中的“保留空间”大小是数字 每页末尾的字节空间,以保留扩展名。 此值通常为 0。该值可能是奇数。

数据库页的“可用大小”是 标头中偏移量 16 处的 2 字节整数减去“保留”空间大小 记录在标头偏移量 20 处的 1 字节整数中。可用 页面大小可能是奇数。但是,可用尺寸不是 允许小于 480。换句话说,如果页面大小为 512, 则预留空间大小不能超过 32。

1.3.5. 有效载荷分数

最大和最小嵌入有效载荷分数和叶片 有效负载分数值必须为 64、32 和 32。这些值是 最初打算成为可用于 修改 B 树算法的存储格式。但是,那 不支持功能,并且当前没有要添加的计划 未来的支持。因此,这三个字节固定在 指定的值。

1.3.6. 文件更改计数器

文件更改计数器是一个 4 字节的大端整数,位于 每当数据库文件解锁时递增的偏移量 24 修改后。 当两个或多个进程读取同一个数据库文件时,每个进程 进程可以通过监视来检测来自其他进程的数据库更改 找零钱计数器。 在以下情况下,进程通常希望刷新其数据库页缓存 另一个进程修改了数据库,因为缓存已过时。 文件更改计数器便于执行此操作。

在 WAL 模式下,使用 wal-index 检测对数据库的更改 因此不需要找零计数器。因此,更改计数器可能 在 WAL 模式下,每个事务都不会递增。

1.3.7. Header 数据库大小

偏移量为 28 处的 4 字节大端整数进入标头 以页为单位存储数据库文件的大小。如果此 in-header datasize size 无效(见下一段),则数据库 大小是通过查看来计算的 以数据库文件的实际大小。SQLite 的旧版本 忽略头数据库大小,使用实际文件大小 惟独。较新版本的 SQLite 使用 in-header 数据库 size(如果可用),但回退到实际文件大小,如果 In-Header 数据库大小无效。

仅当以下情况时,才认为标头内数据库大小有效 它不为零,如果 4 字节更改计数器在偏移量 24 处 与偏移量 92 处的 4 字节 version-valid-for 数字完全匹配。 标头内数据库大小始终有效 当仅使用最新版本的 SQLite 修改数据库时, 版本 3.7.0 (2010-07-21) 及更高版本。 如果旧版本的SQLite写入数据库,则不会 知道更新 In-Header 数据库大小,因此 In-Header 数据库大小可能不正确。但是SQLite的旧版本 还将保持偏移量 92 处的 version-valid-for 编号不变 所以它不会与更改计数器匹配。因此,无效的 in-header 可以通过观察何时来检测(并忽略)数据库大小 更改计数器与 version-valid-for 编号不匹配。

1.3.8. 免费页面列表

数据库文件中未使用的页面存储在自由列表上。这 偏移量 32 处的 4 字节大端整数存储 自由列表的第一页,如果自由列表为空,则为零。 偏移量 36 处的 4 字节大端整数存储总计 自由列表上的页数。

架构 cookie 是一个偏移量为 40 的 4 字节大端整数 每当数据库架构发生更改时,该值都会递增。一个 准备好的语句是针对特定版本的 数据库架构。当数据库架构发生更改时,语句 必须重新准备。当准备好的语句运行时,它首先检查 架构 cookie,以确保值与语句时的值相同 已准备,如果架构 cookie 已更改,则语句 自动重新准备并重新运行,否则会因SQLITE_SCHEMA错误而中止。

1.3.10. 模式格式编号

架构格式编号是偏移量为 44 处的 4 字节大端整数。 架构格式编号类似于文件格式读取和写入 偏移量 18 和 19 处的版本号,但架构格式号除外 指高级 SQL 格式,而不是低级 b 树 格式。目前定义了四个架构格式编号:

  1. 格式 1 被所有版本的 SQLite 理解到版本 3.0.0 (2004-06-18)。
  2. 格式 2 添加了同一表中行的功能 具有不同数量的列,以支持 ALTER TABLE ...ADD COLUMN 功能。支持 读写格式 2 在 2005-02-20 的 SQLite 版本 3.1.3 中添加了。
  3. 格式 3 添加了 ALTER TABLE 添加的额外列的功能...ADD COLUMN 设置为非 NULL 默认值 值。此功能是在 2005-03-11 的 SQLite 版本 3.1.4 中添加的。
  4. 格式 4 导致 SQLite 遵循 DESC 关键字 on 索引声明。(DESC 关键字在索引中被忽略 格式 1、2 和 3。 格式 4 还添加了两个新的布尔记录类型值(序列号类型 8 和 9)。在 SQLite 3.3.0 中添加了对格式 4 的支持 2006-01-10.

默认情况下,SQLite 创建的新数据库文件使用格式 4。 legacy_file_format编译指示可用于导致 SQLite 使用格式 1 创建新的数据库文件。 格式版本号可以通过以下方式默认为 1 而不是 4 在编译时设置 SQLITE_DEFAULT_FILE_FORMAT=1。

1.3.11. 建议的缓存大小

偏移量为 48 处的 4 字节大端有符号整数是建议的 数据库文件的缓存大小(以页为单位)。该值是一个建议 只有,SQLite没有义务履行它。绝对值 的整数用作建议的大小。建议的缓存大小 可以使用default_cache_size Pragma 进行设置。

1.3.12. 增量真空设置

使用偏移量 52 和 64 处的两个 4 字节大端整数 管理auto_vacuum和incremental_vacuum模式。如果 偏移量 52 处的整数为零,则指针映射 (PTRMAP) 页面为 从数据库文件中省略,既不auto_vacuum也不 支持incremental_vacuum。如果偏移量 52 处的整数为 非零,则它是 数据库文件,数据库文件将包含 ptrmap 页面,并且 mode 必须是 auto_vacuum 或 incremental_vacuum。在后者中 情况下,偏移量 64 处的整数对于 incremental_vacuum 和 auto_vacuum为 false。如果偏移量 52 处的整数为零,则 偏移量 64 处的整数也必须为零。

1.3.13. 文本编码

偏移量 56 处的 4 字节大端整数确定编码 用于存储在数据库中的所有文本字符串。 值为 1 表示 UTF-8。 值 2 表示 UTF-16le。 值 3 表示 UTF-16be。 不允许使用其他值。 sqlite3.h 头文件将 C 预处理器宏SQLITE_UTF8定义为 1, SQLITE_UTF16LE 为 2,SQLITE_UTF16BE为 3,用于代替 文本编码的数字代码。

1.3.14. 用户版本号

偏移量为 60 处的 4 字节大端整数是用户版本,其 由user_version Pragma 设置和查询。用户版本是 SQLite未使用。

1.3.15. 应用程序 ID

偏移量 68 处的 4 字节大端整数是一个“应用程序 ID”,它 可以通过 PRAGMA application_id 命令进行设置,以识别 数据库属于特定应用程序或与特定应用程序相关联。 应用程序 ID 用于用作应用程序文件格式的数据库文件。应用程序 ID 可由实用程序使用 比如 file(1) 来确定具体的 文件类型,而不仅仅是报告“SQLite3 数据库”。列表 通过查阅 SQLite 源存储库中的 magic.txt 文件,可以查看分配的应用程序 ID。

1.3.16. 写入库版本号和版本有效号

偏移量 96 处的 4 字节大端整数存储了 SQLite 库的SQLITE_VERSION_NUMBER值,该值最 最近修改了数据库文件。4 字节大端整数 偏移量 92 是版本号时更改计数器的值 被存储。偏移量 92 处的整数表示哪个事务 版本号对 有效,有时称为 “version-valid-for 编号”。

1.3.17. 为扩展保留的标题空间

数据库文件头的所有其他字节都保留给 将来的扩展,并且必须设置为零。

1.4. 锁字节页面

锁字节页是数据库文件的单个页 包含 1073741824 和 1073742335 之间偏移的字节, 包容。小于或等于 1073741824 字节的数据库文件 in size 不包含锁字节页。大于 1073741824只包含一个锁字节页。

锁字节页被留出,供特定于操作系统的 VFS 实现在实现数据库文件锁定基元时使用。 SQLite 不使用锁字节页。SQLite核心 永远不会读取或写入锁字节页, 尽管特定于操作系统的 VFS 实现可以选择在锁字节上读取或写入字节 页面根据 底层系统的需求和倾向。内置到 SQLite 中的 unix 和 win32 VFS 实现不会写入 锁定字节页面,但第三方 VFS 实现 其他操作系统可能。

锁字节页面源于支持 Win95 的需要,Win95 是 设计此文件格式时的主要操作系统以及 仅支持强制文件锁定。所有现代操作系统 我们知道支持咨询文件锁定,因此锁定字节页面是 实际上不再需要,但保留以向后兼容。

1.5. 自由列表

数据库文件可能包含一个或多个不在 积极使用。例如,当信息出现时,可能会出现未使用的页面 将从数据库中删除。未使用的页面存储在自由列表中 并在需要其他页面时重复使用。

freelist 被组织为自由列表主干页面的链表 每个主干页面都包含零个或多个 freelist 的页码 叶页。

freelist 主干页面由一个 4 字节大端整数数组组成。 数组的大小与可用空间中容纳的整数一样多 一页。最小可用空间为 480 字节,因此数组将始终 长度至少为 120 个条目。freelist 主干上的第一个整数 page 是列表中下一个 freelist 主干页面的页码或零 如果这是最后一个 freelist 主干页面。自由列表上的第二个整数 主干页是要遵循的叶页指针的数量。 调用自由列表主干页 L 上的第二个整数。 如果 L 大于零,则数组索引介于 2 和 之间的整数 L+1(含)包含自由列表叶页的页码。

自由列表叶页不包含任何信息。SQLite 避免读取或 编写 freelist 叶页以减少磁盘 I/O。

3.6.0 之前的 SQLite 版本中的错误 (2008-07-16) 导致数据库 如果 Freelist 主干页面中的最后 6 个条目中的任何一个被报告为损坏 数组包含非零值。较新版本的 SQLite 没有 这个问题。但是,较新版本的 SQLite 仍然避免使用 Freelist 主干页面数组中的最后六个条目,以便该数据库 由较新版本的 SQLite 创建的文件可以由旧版本读取 的 SQLite。

自由列表页数存储为 4 字节大端整数 在数据库标头中,与文件开头的偏移量为 36。 数据库头还存储第一个自由列表主干的页码 page 作为 4 字节大端整数,从开头偏移量为 32 的文件。

1.6. B树页面

b 树算法提供具有唯一和 面向页面的存储设备上的排序键。 有关 b 树的背景信息,请参阅 b 树。 Knuth,《计算机编程的艺术》,第 3 卷“排序” 和搜索“,第 471-479 页。b 树的两种变体由 SQLite的。“表 b 树”使用 64 位有符号整数键并存储 叶子中的所有数据。“索引 b 树”使用任意键并存储 no 根本没有数据。

b 树页可以是内页,也可以是叶页。 叶页包含键,如果是表,则包含每个键 b 树 键具有关联的数据。内页包含 K 键以及指向子 b 树页面的 K+1 指针。 内部 b 树页面中的“指针”只是 32 位 子页的无符号整数页码。

内部 b 树页面上的键数,K, 几乎总是至少 2,并且通常远大于 2。 唯一的例外是第 1 页是内部 b 树页面。 第 1 页的可用存储空间减少了 100 个字节, 由于该页面开头存在数据库标头, 因此,有时(很少)如果第 1 页是内部 B 树页面,它可以 最终只拿着一把钥匙。在所有其他情况下,K 为 2 或更多。 K 上的上限是页面上适合的键数。大键 在索引 B 上,树被拆分为溢出页,因此没有单个键 占用页面上四分之一以上的可用存储空间 因此,每个内部页面都能够存储至少 4 个密钥。 表 b 树的整数键永远不够大,无法 需要溢出,因此键溢出仅发生在索引 B 树上。

定义深度 叶子 B 树的深度为 1,任何内部 B 树的深度为 1 超过其任何子项的最大深度。在格式良好的 数据库中,内部 B 树的所有子级都具有相同的深度。

在内部 b 树页面中,指针和键在逻辑上交替 两端都有一个指针。(前一句是要理解的 从概念上讲 - 按键的实际布局和 页面中的指针更复杂,将在 续集。同一页面中的所有键都是唯一的,并且在逻辑上是 按从左到右的升序排列。(同样,这个顺序 是合乎逻辑的,而不是物理的。键在页面中的实际位置 是任意的。对于任何键 X,指向左侧的指针 的 X 是指所有键都小于或等于 X 的 b 树页面。 X 右侧的指针是指所有键所在的页面 大于 X。

在内部 b 树页面中,每个键和指向其的指针 紧挨着的左边被组合成一个称为“细胞”的结构。这 最右边的指针是分开的。叶子 b 树页面没有 指针,但它仍然使用单元格结构来保存 索引 B 树或表 B 树的键和内容。数据也是 包含在单元格中。

每个 b 树页面最多有一个父 b 树页面。 没有父级的 b 树页面称为根页面。根 b 树页面 连同其子项的闭合一起形成一个完整的 B 树。 有一个完整的 b 树是可能的(事实上很常见) 它由一个既是叶子又是根的页面组成。 因为有从父母到孩子的指针,所以每一页 如果只知道根页,则可以找到完整的 B 树。因此 B 树由其根页码标识。

b 树页可以是表 b 树页,也可以是索引 b 树页。 每个完整的 b 树中的所有页面都属于同一类型:任一表 或索引。数据库文件中有一个表 b 树 对于数据库架构中的每个 RowID 表,包括系统表 比如sqlite_schema。有一个索引 b 树 在架构中每个索引的数据库文件中,包括隐含索引 由唯一性约束创建。没有与虚拟表关联的 b 树。特定的虚拟表实现可能会使用 用于存储的影子表,但这些影子表将具有单独的 数据库架构中的条目。没有 ROWID 表,请使用索引 b 树 而不是一个表 b 树,所以有一个 在数据库文件中为每个 WITHOUT ROWID 表编制索引 b 树。 与sqlite_schema表对应的 b 树始终是表 b-tree 并且始终具有 1 的根页。 sqlite_schema表包含每隔一个的根页码 数据库文件中的表和索引。

表 b 树中的每个条目都由一个 64 位有符号整数键组成 以及最多 2147483647 字节的任意数据。(表 b 树的键 对应于 b 树实现的 SQL 表的 rowid。 内部桌子 b 树只装钥匙和指向儿童的指针。 所有数据都包含在表 b 树叶中。

索引 b 树中的每个条目都由一个任意键 up 组成 长度为 2147483647 字节,没有数据。

将单元格的“有效负载”定义为任意长度部分 的细胞。对于索引 b 树,键的长度始终是任意的 因此,有效载荷是关键。没有任意长度的元素 在内部表 B 树页面的单元格中,因此这些单元格没有 有效载荷。表 b 树叶页包含任意长度的内容和 因此,对于这些页面上的单元格,有效负载是内容。

当单元的有效载荷大小超过某个阈值(至 稍后定义),则仅有效负载的前几个字节 存储在B树页面,余额存储在链表中 的内容溢出页面。

b树页面按以下顺序划分为多个区域:

  1. 100 字节数据库文件头(仅在第 1 页上找到)
  2. 8 或 12 字节的 b 树页眉
  3. 单元格指针数组
  4. 未分配的空间
  5. 单元格内容区域
  6. 保留区域。

100 字节的数据库文件头仅在第 1 页找到,即 始终是表 B 树页面。数据库文件中的所有其他 b 树页 省略此 100 字节标头。

保留区域是每个末尾的未使用空间区域 页面(锁定页面除外),扩展程序可以使用它来保留每个页面 信息。保留区域的大小由一个字节决定 在数据库文件头的偏移量为 20 处找到的无符号整数。 保留区域的大小通常为零。

对于叶页,b 树页眉的大小为 8 个字节,而叶页的页眉大小为 12 个字节 内页的字节。页眉中的所有多字节值 是大端的。 b-tree 页眉由以下字段组成:

B-tree 页眉格式

偏移大小说明
01偏移量为 0 处的单字节标志,指示 b 树页面类型。
  • 值 2 (0x02) 表示该页是内部索引 b 树页。
  • 值 5 (0x05) 表示该页是内部表 b 树页。
  • 值 10 (0x0a) 表示该页是叶索引 b 树页。
  • 值 13 (0x0d) 表示该页是叶表 b 树页。
b 树页面类型的任何其他值都是错误。
12偏移量 1 处的双字节整数给出了 页面上的第一个 freeblock,如果没有 freeblocks,则为零。
32偏移量 3 处的双字节整数给出页面上的单元格数。
52偏移量 5 处的双字节整数指定单元格内容的开始 面积。此整数的零值被解释为 65536。
71偏移量 7 处的一字节整数给出了自由碎片的数量 单元格内容区域中的字节。
84偏移量 8 处的四字节页码是最右边的指针。这 value 仅出现在内部 B 树页面的标题中,并且从 所有其他页面。

b 树页面的单元格指针数组紧跟在 b 树之后 页眉。设 K 是 btree 上的单元格数。单元格指针 数组由单元格内容的 K 个 2 字节整数偏移量组成。这 单元格指针按键顺序排列,最左边的单元格(具有 最小的键)和最右边的单元格(具有最大键的单元格) key)最后。

单元格内容存储在 b 树页面的单元格内容区域中。 SQLite努力将单元格放置在b树页面的末尾,因为 它可以,以便为单元格指针数组的未来增长留出空间。 最后一个单元格指针数组条目和 第一个单元格是未分配的区域。

如果页面不包含单元格(仅适用于根页面) 不包含行的表),则偏移量为 单元格内容区域将等于页面大小减去保留空间的字节数。 如果数据库使用 65536 字节的页面大小,并且保留空间为零 (保留空间的通常值),然后单元格内容偏移量 空页希望为 65536。 但是,该整数太大,无法存储在 2 字节无符号整数,因此在其位置使用值 0。

自由块是一种结构,用于识别其中未分配的空间 B 树页面。Freeblocks被组织成一个链。前 2 个字节 freeblock 是一个 big-endian 整数,它是 b 树页面中的偏移量 链中的下一个自由区块,如果自由区块是最后一个自由区块,则为零 链条。每个自由块形式的第三个和第四个字节 一个大端整数,其大小为 freeblock 的大小(以字节为单位),包括 4 字节标头。Freeblocks 始终按顺序连接 增加抵消量。b-tree 页眉的第二个字段是 第一个自由块的偏移量,如果 页。在格式良好的 b 树页面中,始终至少有一个单元格 在第一个 freeblock 之前。

一个 freeblock 至少需要 4 个字节的空间。如果有一个隔离的 单元格内容区域中 1、2 或 3 个未使用的字节组,这些字节 组成一个片段。存储所有片段中的总字节数 在 B 树页眉的第五个字段中。在格式良好的 b 树页面中, 片段中的总字节数不得超过 60 个。

b 树页面上的可用空间总量由 未分配的区域加上所有自由块的总大小加上 碎片可用字节数。SQLite可能会不时重组 一个 B 树页面,这样就没有 freeblocks 或 fragment 字节,所有 未使用的字节包含在未分配的空间区域中,并且所有 单元格在页面末尾紧密包装。这叫做 对 B 树页面进行“碎片整理”。

可变长度整数或“varint”是静态霍夫曼编码 的 64 位二进制补码整数,为小正数使用更少的空间 值。 变量的长度介于 1 到 9 个字节之间。变量由以下任一部分组成 零个或多个字节,其中设置了高阶位,后跟一个字节 高阶位为clear,或9个字节,以较短者为准。 前 8 个字节中每个字节的下 7 位和 第九个字节用于重建 64 位二进制补码整数。 Varint 是 big-endian:取自 varint 的较早字节的位 比从后面的字节中获取的位更重要。

单元格的格式取决于单元格的 b 树页面类型 出现在。下表显示了单元格的元素,在 出现顺序,适用于各种 B 树页面类型。

表 B 树叶单元格(标题 0x0d):

  • 一个变量,它是有效负载的总字节数,包括 溢出
  • 作为整数键的变量,又名“rowid”"
  • 有效负载的初始部分,不会溢出到溢出 页面。
  • 一个 4 字节大端整数页码,用于 溢出页面列表 - 如果所有有效负载都适合 B 树页面,则省略。

表 B 树内部单元格(标题 0x05):

  • 一个 4 字节的大端页码,它是左子指针。
  • 作为整数键的变量

索引 B 树叶单元格(标题 0x0a):

  • 一个变量,它是密钥有效负载的总字节数,包括 溢出
  • 有效负载的初始部分,不会溢出到溢出 页面。
  • 一个 4 字节大端整数页码,用于 溢出页面列表 - 如果所有有效负载都适合 B 树页面,则省略。

索引 B 树内部单元格(标题 0x02):

  • 一个 4 字节的大端页码,它是左子指针。
  • 一个变量,它是密钥有效负载的总字节数,包括 溢出
  • 有效负载的初始部分,不会溢出到溢出 页面。
  • 一个 4 字节大端整数页码,用于 溢出页面列表 - 如果所有有效负载都适合 B 树页面,则省略。

上述信息可以转换为表格格式,如下所示:

B-tree 单元格格式

数据类型出现在...说明
表叶节点类型 (0x0d)表内部节点类型 (0x05)索引叶节点类型 (0x0a)索引内节点类型 (0x02)
4 字节整数左边子项的页码
varint有效负载的字节数
varint罗维德
字节数组有效载荷
4 字节整数第一个溢出页的页码

溢出到溢出页面的有效负载量还取决于 页面类型。对于以下计算,设 U 为可用大小 ,总页面大小减去 每页的末尾。设 P 为有效载荷大小。在下文中, 符号 X 表示可直接存储的最大有效载荷量 在 b 树页面上,而不会溢出到溢出页面和符号 M 上 表示必须存储在 btree 上的最小有效负载量 允许溢出前的页面。

表 B 树叶单元:

设 X 为 U-35。如果有效载荷大小 P 小于或等于 X,则 整个有效负载存储在 B-Tree 叶页上。 设 M 为 ((U-12)*32/255)-23,设 K 为 M+((P-M)%(U-4))。 如果 P 大于 X 则表b树叶页上存储的字节数为K 如果 K 小于或等于 X 或 M,否则。 叶页上存储的字节数永远不会小于 M。

表 B-树内部单元:

表 b 树的内页没有有效载荷,因此永远不会有 任何要溢出的有效载荷。

索引 B 树叶或内部单元格:

设 X 为 ((U-12)*64/255)-23。如果有效载荷大小 P 小于 或等于 X,则整个有效负载存储在 b 树页面上。 设 M 为 ((U-12)*32/255)-23,设 K 为 M+((P-M)%(U-4))。 如果 P 大于 X,则 如果 K 小于 或 否则等于 X 或 M。 索引页上存储的字节数永远不会小于 M。

以下是相同计算的替代描述:

  • X 是 U-35,用于表 btree 叶页或 ((U-12)*64/255)-23 用于索引页。
  • M 始终为 ((U-12)*32/255)-23。
  • 设 K 为 M+((P-M)%(U-4))。
  • 如果 P<=X,则有效负载的所有 P 字节都直接存储在 没有溢出的 btree 页面。
  • 如果 P>X 和 K<=X,则 P 的前 K 个字节存储在 btree 页面和剩余的 P-K 字节存储在溢出页面上。
  • 如果 P>X 和 K>X,则 P 的前 M 字节存储在 btree 页面和剩余的 P-M 字节存储在溢出页面上。

溢出阈值旨在提供 4 用于索引 b 树,并确保足够的有效载荷 位于通常可以访问记录标头的 B 树页面上 无需咨询溢出页面。事后看来,设计师 SQLite b-tree 逻辑意识到这些阈值可能是 变得简单多了。但是,无法更改计算 而不会导致不兼容的文件格式。和当前的计算 工作得很好,即使它们有点复杂。

1.7. 单元格有效负载溢出页面

当 b-tree 单元格的有效负载对于 b 树页面来说太大时, 多余的内容会溢出到溢出页面上。溢出页面形成链接 列表。每个溢出页的前四个字节都是一个大端 整数,即链中下一页的页码,或零 对于链中的最后一页。第五个字节到最后一个可用字节 字节用于保存溢出内容。

1.8. 指针映射或 Ptrmap 页面

指针映射或 ptrmap 页面是插入到数据库中的额外页面 使auto_vacuum和incremental_vacuum模式的操作 效率更高。数据库中的其他页面类型通常具有指针 从父母到孩子。例如,内部 b 树页面包含指针 到其子 B 树页面,溢出链具有指针 从链条中的早期链接到后期链接。ptrmap 页面包含链接 信息朝着相反的方向发展,从子项到父级。

Ptrmap 页面必须存在于任何具有非零的数据库文件中 数据库标头中偏移量为 52 处的最大根 B 树页面值。 如果最大根 b 树页面值为零,则数据库不得 包含 ptrmap 页面。

在具有 ptrmap 页面的数据库中,第一个 ptrmap 页面是第 2 页。 ptrmap 页面由一个 5 字节条目的数组组成。设 J 为 适合页面可用空间的 5 字节条目数。 (换言之,J=U/5。第一个 ptrmap 页面将包含返回指针 第 3 页到 J+2 页的信息(含)。第二个指针映射 页面将位于 J+3 页上,该 ptrmap 页面将提供反向指针 J+4 至 2*J+3(含)页面的信息。依此类推 整个数据库文件。

在使用 ptrmap 页面的数据库中,标识位置的所有页面 通过上一段中的计算必须是 ptrmap 页面而不是 其他页面可能是 PTRmap 页面。除非,如果字节锁定页面碰巧 落在与 ptrmap 页面相同的页码上,然后移动 ptrmap 到该案例的下一页。

ptrmap 页面上的每个 5 字节条目都提供以下方面的反向链接信息: 紧跟在指针映射后面的页面之一。如果页面 B 是 ptrmap页面,则B+1页面的反向链接信息由以下机构提供 指针映射上的第一个条目。关于页面 B+2 的信息是 由第二个条目提供。等等。

每个 5 字节的 ptrmap 条目由一个字节的“页面类型”信息组成 后跟一个 4 字节的 big-endian 页码。可识别五种页面类型:

  1. b 树根页。这 页码应为零。
  2. 自由列表页面。页码应为 零。
  3. 第一页 单元有效载荷溢出链。页码是 b 树页面 包含内容已溢出的单元格。
  4. 溢出链中的页面 第一页除外。页码是 溢流链。
  5. 非根 b 树页面。这 页码是父 B 树页面。

在任何包含 ptrmap 页的数据库文件中,所有 b 树根页 必须位于任何非根 B 树页面、单元有效负载溢出页面之前,或者 freelist 页面。此限制可确保根页面永远不会 在自动真空或增量真空期间移动。自动吸尘器 逻辑不知道如何更新sqlite_schema的root_page字段 表,因此有必要防止根页面被移动 在自动真空期间,为了保持 sqlite_schema表。根页面将移动到 数据库文件由 CREATE TABLE、CREATE INDEX、DROP TABLE 和 DROP INDEX 操作。

2. 架构层

上述文本描述了 SQLite 文件的低级方面 格式。b-tree 机制提供了一种强大而高效的 访问大型数据集。本节将介绍如何 低级 B 树层用于实现更高级别的 SQL 能力。

2.1. 记录格式

表 b 树叶页的数据和键 索引 B 树页面的特征如上所述 作为任意字节序列。 前面的讨论提到一个键比另一个键少,但是 没有定义“小于”的含义。本节将讨论 这些遗漏。

有效负载,表 b 树数据或索引 b 树键, 始终采用“记录格式”。 记录格式定义了对应的值序列 添加到表或索引中的列。记录格式指定数字 列数、每列的数据类型以及每列的内容。

记录格式广泛使用上面定义的 64 位有符号整数的可变长度整数或可变表示形式。

记录按此顺序包含标头和正文。 标头以单个变量开头,该变量确定总数 的字节数。varint 值是 字节,包括 Size varint 本身。以下尺寸变量是 一个或多个附加变量,每列一个变量。这些额外的变量 称为“序列号”编号和 根据下图确定每列的数据类型:

记录格式的串行类型代码

串行类型内容大小意义
00Value 为 NULL。
11value 是一个 8 位二进制补码整数。
22value 是一个大端 16 位二进制补码整数。
33Value 是一个 big-endian 24 位二进制补码整数。
44Value 是一个 big-endian 32 位二进制补码整数。
56Value 是一个 big-endian 48 位二进制补码整数。
68value 是一个 big-endian 64 位二进制补码整数。
78值是大端 IEEE 754-2008 64 位浮点数。
80值为整数 0。(仅适用于架构格式 4 及更高版本。
90值是整数 1。(仅适用于架构格式 4 及更高版本。
10,11变量保留供内部使用。这些序列号类型代码将 永远不会出现在格式正确的数据库文件中,但它们 可能在瞬态数据库文件和临时数据库文件中使用 SQLite有时会生成供自己使用。 这些代码的含义可以从一个版本中转移 的 SQLite 到下一个。
N≥12 甚至(N-12)/2值是长度为 (N-12)/2 字节的 BLOB。
N≥13 和奇数(N-13)/2Value 是文本编码中的字符串,长度为 (N-13)/2 字节。 不存储 nul 终结符。

标头大小变量 串行类型 varint 通常由单个字节组成。这 大型字符串和 BLOB 的串行类型 varint 可能会扩展到两个或三个 字节变量,但这是例外而不是规则。 varint 格式在编码记录标头时非常有效。

记录中每列的值紧跟在标题之后。 对于串行类型 0、8、9、12 和 13,该值为零字节 长度。如果所有列都属于这些类型,则 记录为空。

记录的值可能少于 对应表。例如,这可能发生在 ALTER TABLE 之后......ADD COLUMN SQL 语句已增加 表架构中不修改预先存在的行的列数 在表中。 使用表架构中定义的相应列的默认值填充记录末尾的缺失值。

2.2. 记录排序顺序

索引 b 树中键的顺序由 键所表示的记录。记录比较进度列 按列。从左到右检查记录的列。这 第一对不相等的列决定了相对顺序 两条记录。各列的排序顺序如下 遵循:

  1. NULL 值(序列号类型 0)首先排序。
  2. 数值(序列号类型 1 到 9)在 NULL 之后排序 并按数字顺序排列。
  3. 文本值(奇数序列类型 13 及更大)在数值后排序 按列排序函数确定的顺序排列的值。
  4. BLOB 值(甚至序列号类型 12 及更大)按顺序排在最后 由 memcmp() 确定。

为了计算,每列的整理函数是必需的 文本字段的顺序。 SQLite定义了三个内置的排序函数:

二元的内置的 BINARY 排序规则可逐字节比较字符串 使用 memcmp() 函数 来自标准 C 库。
NOCASE公司NOCASE 排序规则与 BINARY 类似,只是大写 ASCII 字符(“A”到“Z”) 在运行 比较。只有 ASCII 字符是大小写折叠的。 NOCASE公司 不实现通用的 Unicode 无大小写比较。
RTRIM的RTRIM 类似于 BINARY,只是在两者的末尾有额外的空格 字符串不会更改结果。换句话说,字符串将 只要它们相互比较 区别仅在于末尾的空格数。

可以添加其他特定于应用程序的整理功能 使用 sqlite3_create_collation() 接口的 SQLite。

所有字符串的默认排序函数是 BINARY。 可以在 CREATE TABLE 语句中使用列定义上的 COLLATE 子句指定表列的替代排序函数。 为列编制索引时,默认情况下,CREATE TABLE 语句中指定的相同排序规则函数将用于索引中的列, 尽管可以使用 CREATE INDEX 语句中的 COLLATE 子句覆盖此内容。

2.3. SQL表的表示

数据库架构中的每个普通 SQL 表都表示在磁盘上 由表 B 树。表 b 树中的每个条目对应一行 的 SQL 表。SQL 表的 rowid 是 64 位有符号的 表 B 树中每个条目的整数键。

每个 SQL 表行的内容通过以下方式存储在数据库文件中 首先将各列中的值组合成一个字节数组 ,然后将该字节数组存储为有效负载 表 B 树中的条目。记录中值的顺序为 与 SQL 表定义中的列顺序相同。 当 SQL 表包含 INTEGER PRIMARY KEY 列(别名为 rowid)时,则 列在记录中显示为 NULL 值。SQLite 将始终使用 引用 INTEGER PRIMARY KEY 列时,表 b 树键而不是 NULL 值。

如果列的亲和力为 REAL,并且该列包含 可以在不丢失信息的情况下转换为整数的值 (如果该值不包含小数部分,并且不会太大而不能 表示为整数),则该列可以存储在记录中 作为整数。SQLite 会将值转换回浮点 从记录中提取它时的点。

2.4. WITHOUT ROWID表的表示

如果使用 “WITHOUT ROWID” 子句创建 SQL 表 在其 CREATE TABLE 语句的末尾,则该表是 WITHOUT ROWID 表,并使用不同的磁盘表示形式。A 不带 ROWID 表使用索引 B 树而不是表 B 树进行存储。 WITHOUT ROWID b 树中每个条目的键都是一条记录 的列 PRIMARY KEY 后跟 桌子。主键列按其显示顺序显示 在 PRIMARY KEY 子句中声明,其余列出现在 它们在 CREATE TABLE 语句中出现的顺序。

因此,WITHOUT ROWID 表的内容编码是相同的 作为普通 rowid 表的内容编码,除了 重新排列列的顺序,以便 PRIMARY KEY 列出现 首先,内容用作索引 B 树中的键,而不是 而不是作为表 b 树中的数据。 具有 REAL 亲和力的列的特殊编码规则 应用于 WITHOUT ROWID 表的方式与应用于 rowid 表相同。

2.4.1. 禁止 PRIMARY KEY 中的冗余列 的 WITHOUT ROWID 表

如果 WITHOUT ROWID 表的 PRIMARY KEY 使用相同的列 多次使用相同的排序顺序,然后是第二个和 该列在 PRIMARY KEY 定义中的后续出现项为 忽视。例如,以下 CREATE TABLE 语句都指定 同一个表,在磁盘上将具有完全相同的表示形式:

CREATE TABLE t1(a,b,c,d,PRIMARY KEY(a,c)) WITHOUT ROWID;
CREATE TABLE t1(a,b,c,d,PRIMARY KEY(a,c,a,c)) WITHOUT ROWID;
CREATE TABLE t1(a,b,c,d,PRIMARY KEY(a,A,a,C)) WITHOUT ROWID;
CREATE TABLE t1(a,b,c,d,PRIMARY KEY(a,a,a,a,c)) WITHOUT ROWID;

上面的第一个示例是表的首选定义, 答案是肯定的。所有示例都创建一个 WITHOUT ROWID 表,其中包含 两个 PRIMARY KEY 列,“a”和“c”,按此顺序排列,后跟 两个数据列“B”和“D”,也按此顺序排列。

2.5. SQL索引的表示

每个 SQL 索引,是否通过 CREATE INDEX 语句显式声明 或由 UNIQUE 或 PRIMARY KEY 约束暗示,对应于 数据库文件中的索引 B 树。 索引 b 树中的每个条目对应于 关联的 SQL 表。 索引 b 树的关键是 由正在编制索引的列组成的记录,后跟 对应表行的键。对于普通表,行键为 rowid,对于 WITHOUT ROWID 表,行键是 PRIMARY KEY。 因为表中的每一行都有一个唯一的行键, 索引中的所有键都是唯一的。

在普通索引中,行与行之间存在一对一的映射 表以及与该表关联的每个索引中的条目。 但是,在部分索引中,索引 b 树仅包含条目 对应于表行,其中 WHERE 子句表达式在 CREATE INDEX 语句为 true。 索引树和表 b 树中的相应行共享相同的 rowid 或主键值,并包含所有索引列的相同值。

2.5.1. 抑制 WITHOUT ROWID 二级索引中的冗余列

在 WITHOUT ROWID 表的索引中,如果 PRIMARY KEY 的列 也是索引中的一列,并且具有匹配的排序顺序,则 索引列在 table-key 后缀中不会重复 索引记录的末尾。例如,请考虑以下 SQL:

CREATE TABLE ex25(a,b,c,d,e,PRIMARY KEY(d,c,a)) WITHOUT rowid;
CREATE INDEX ex25ce ON ex25(c,e);
CREATE INDEX ex25acde ON ex25(a,c,d,e);
CREATE INDEX ex25ae ON ex25(a COLLATE nocase,e);

ex25ce 索引中的每一行都是一条记录 使用这些列:C、E、D、A。前两列是 要编制索引的列 c 和 e。其余列是主列 对应表行的键。通常,主键为 列 d、c 和 a,但因为 c 列已经出现在 索引,则从键后缀中省略它。

在极端情况下,被索引的列覆盖所有列 的 PRIMARY KEY,索引将仅包含以下列 索引。上面的 ex25acde 示例演示了这一点。每个条目 EX25ACDE 索引仅包含列 A、C、D 和 E,其中 次序。

ex25ae 中的每一行包含五列:a、e、d、c、a。“a” 列重复,因为第一次出现的“a”具有整理 函数为“nocase”,第二个具有“binary”的整理序列。 如果“a”列不重复,并且表包含两个或更多 具有相同“e”值的条目,其中“a”仅在大小写上有所不同,则 所有这些表条目将对应于 索引,这将破坏表之间的一对一对应关系 和索引。

禁止显示索引键后缀中的冗余列 条目仅出现在 WITHOUT ROWID 表中。在一个普通的吵闹表中, 索引条目始终以 rowid 结尾,即使 INTEGER PRIMARY KEY 列是要编制索引的列之一也是如此。

2.6. SQL 数据库架构的存储

数据库文件的第 1 页是表 b 树的根页,该 有一张名为“sqlite_schema”的特殊表。这个 b 树是已知的 作为“架构表”,因为它存储了完整的 数据库架构。sqlite_schema表的结构如下 如果它是使用以下 SQL 创建的:

CREATE TABLE sqlite_schema(type text,name text,tbl_name text,rootpage integer,sql text
);

sqlite_schema表包含每个表、索引、视图、 和触发器(统称为“对象”)在数据库架构中,但 不是 sqlite_schema 表本身的条目。sqlite_schema表 除了 application- 之外,还包含内部架构对象的条目 和程序员定义的对象。

sqlite_schema.type 列将为 1 以下文本字符串:“table”、“index”、“view”或“trigger” 根据定义的对象类型。使用“table”字符串 适用于普通表和虚拟表。

sqlite_schema.name 列将保存对象的名称。表的 UNIQUE 和 PRIMARY KEY 约束导致 SQLite 创建名称形式为“sqlite_autoindex_TABLE_N”的内部索引 其中 TABLE 替换为包含 constraint 和 N 是以 1 开头并递增 1 的整数 在表定义中可以看到的每个约束。 在 WITHOUT ROWID 表中,没有 sqlite_schema 条目 PRIMARY KEY,但“sqlite_autoindex_TABLE_N”名称被搁置一旁 对于 PRIMARY KEY,就好像 sqlite_schema 条目确实存在一样。这 将影响后续 UNIQUE 约束的编号。 “sqlite_autoindex_TABLE_N”名称永远不会分配给 INTEGER PRIMARY KEY,无论是在 rowid 表中还是在 WITHOUT ROWID 表中。

sqlite_schema.tbl_name 列保存表或视图的名称 对象与之关联。对于表或视图, tbl_name列是名称列的副本。对于索引,tbl_name 是索引的表的名称。对于触发器,tbl_name 列存储导致触发的表或视图的名称 开火。

sqlite_schema.rootpage 列存储根目录的页码 表和索引的 B 树页面。对于定义视图、触发器、 和虚拟表,rootpage 列为 0 或 NULL。

sqlite_schema.sql 列存储描述 对象。此 SQL 文本是 CREATE TABLE、CREATE VIRTUAL TABLE、CREATE INDEX、CREATE VIEW 或 CREATE TRIGGER 语句,如果根据这些语句进行评估 当数据库文件是数据库连接的主数据库时,它将重新创建对象。文本通常是原件的副本 语句用于创建对象,但应用了规范化 文本符合以下规则:

  • 开头的 CREATE、TABLE、VIEW、TRIGGER 和 INDEX 关键字 的语句转换为全部大写字母。
  • 如果 TEMP 或 TEMPORARY 关键字出现在 初始 CREATE 关键字。
  • 出现在 正在创建的对象将被删除。
  • 前导空格被移除。
  • 前两个关键字后面的所有空格都转换为单个 空间。

sqlite_schema.sql列中的文本是原件的副本 创建对象的 CREATE 语句文本,但规范化为 如上所述,并由后续的 ALTER TABLE 语句修改。 对于以下内部索引,sqlite_schema.sql为 NULL 由 UNIQUE 或 PRIMARY KEY 约束自动创建。

2.6.1. 模式表的替代名称

名称“sqlite_schema”不会出现在文件格式的任何位置。 该名称只是数据库实现使用的约定。 由于历史和运营方面的考虑, “sqlite_schema”表有时也可以由以下之一调用 以下别名:

  1. sqlite_master
  2. sqlite_temp_schema
  3. sqlite_temp_master

因为架构表的名称不会出现在 文件格式,如果出现以下情况,则数据库文件的含义不会改变 应用程序选择通过以下之一来引用架构表 这些替代名称。

2.6.2. 内部模式对象

除了 应用程序和/或开发人员使用 CREATE 语句 SQL、 sqlite_schema表可能包含零个或多个内部架构对象的条目,这些条目由 SQLite 为其创建 自己内部使用。内部架构对象的名称 始终以“sqlite_”和任何表、索引、视图或触发器开头 其名称以“sqlite_”开头是一个内部架构对象。 SQLite 禁止应用程序创建名称以 EACH 开头的对象 带有“sqlite_”。

SQLite 使用的内部架构对象可能包括以下内容:

  • 名称形式为“sqlite_autoindex_TABLE_N”的索引 用于实现 UNIQUE 和 PRIMARY KEY 约束 普通表。

  • 名称为“sqlite_sequence”的表,用于跟踪 表的最大历史整数主键 使用 AUTOINCREMENT。

  • 名称形式为“sqlite_statN”的表,其中 N 为整数。 此类表存储由 ANALYZE 命令收集的数据库统计信息,并由查询规划器用于帮助确定最佳 用于每个查询的算法。

新的内部架构对象名称,始终以“sqlite_”开头, 可能会在将来的版本中添加到 SQLite 文件格式中。

2.6.3. sqlite_sequence表

sqlite_sequence表是用于帮助实现 AUTOINCREMENT 的内部表。自动创建sqlite_sequence表 每当任何具有 AUTOINCREMENT 整数主的普通表时 密钥已创建。创建后,sqlite_sequence表将存在于 永远sqlite_schema桌子;它不能被丢弃。 sqlite_sequence表的架构为:

CREATE TABLE sqlite_sequence(name,seq);

sqlite_sequence表中有一个行对应每个普通 使用 AUTOINCREMENT 的表。表的名称(如 sqlite_schema.name) 位于 sqlite_sequence.name 字段中,并且插入该表的最大整数主键为 在 sqlite_sequence.seq 字段中。 自动生成的 AUTOINCREMENT 的新整数主键 表保证大于 sqlite_sequence.seq 字段 那张桌子。 如果 AUTOINCREMENT 表的 sqlite_sequence.seq 字段已位于 然后,最大整数值 (9223372036854775807) 尝试添加新的 具有自动生成的整数主表的行将失败 出现SQLITE_FULL错误。 如果需要,sqlite_sequence.seq 字段会在以下情况下自动更新 新条目将插入到 AUTOINCREMENT 表中。 自动删除 AUTOINCREMENT 表的sqlite_sequence行 当表格被丢弃时。 如果 AUTOINCREMENT 表的sqlite_sequence行不存在,则在以下情况下 更新 AUTOINCREMENT 表,然后创建新的sqlite_sequence行。 如果 AUTOINCREMENT 表的 sqlite_sequence.seq 值是手动的 设置为整数以外的其他内容,并且随后尝试 插入 AUTOINCREMENT 表或更新 AUTOINCREMENT 表,则行为未定义。

允许应用程序代码修改sqlite_sequence表,以添加 新建行,删除行或修改现有行。但是,应用 如果 sqlite_sequence 表尚不存在,则代码无法创建该表。 应用程序代码可以从sqlite_sequence表中删除所有条目, 但应用程序代码不能删除sqlite_sequence表。

2.6.4. sqlite_stat1表

sqlite_stat1是由 ANALYZE 命令创建的内部表 并用于保存有关表和索引的补充信息,这些信息 查询规划器可用于帮助它找到执行查询的更好方法。 应用程序可以更新、删除、插入或删除sqlite_stat1 表,但不能创建或更改sqlite_stat1表。 sqlite_stat1表的架构如下所示:

CREATE TABLE sqlite_stat1(tbl,idx,stat);

每个索引通常有一行,索引由 sqlite_stat1.idx 列中的 name。sqlite_stat1.tbl 列是 索引所属的表的名称。在每一行中, sqlite_stat.stat 列将是 由整数列表后跟零或多个的字符串组成 参数。其中的第一个整数 list 是索引中的近似行数。(数量 索引中的行数与表中的行数相同, 部分索引除外。 第二个整数是索引中的近似行数 在索引的第一列中具有相同的值。第三个 integer 是索引中具有 前两列的值相同。第 N 个整数(对于 N>1) 是 对前 N-1 列具有相同值的索引。为 一个 K 列索引,则统计列中将有 K+1 个整数。如果 索引是唯一的,则最后一个整数将为 1。

可以选择跟随统计列中的整数列表 by 参数,每个参数都是一系列非空格字符。 所有参数前面都有一个空格。 无法识别的参数将被静默忽略。

如果存在“unordered”参数,则查询规划器假定 索引是无序的,并且不会将索引用于范围查询 或用于排序。

“sz=NNN”参数(其中 NNN 表示 1 位或更多位的序列) 表示表的所有记录的平均行大小或 index 是每行的 NNN 字节数。SQLite 查询规划器可能会使用 “sz=NNN”令牌提供的估计行大小信息 以帮助它选择需要较少磁盘 I/O 的较小表和索引。

sqlite_stat1.stat 字段上存在“noskipscan”令牌 的索引可防止该索引与跳过扫描优化一起使用。

将来可能会将新的文本标记添加到统计列的末尾 对 SQLite 的增强。为了兼容性,末尾有无法识别的令牌 的 stat 列将被静默忽略。

如果 sqlite_stat1.idx 列为 NULL,则 sqlite_stat1.stat 列包含一个整数,它是 表中由 sqlite_stat1.tbl 标识的行。 如果 sqlite_stat1.idx 列与 sqlite_stat1.tbl 相同 列,则该表是 WITHOUT ROWID 表和 sqlite_stat1.stat 字段包含有关实现 没有 ROWID 表。

2.6.5. sqlite_stat2表

仅创建sqlite_stat2,并且仅在编译 SQLite 时使用。 如果 SQLITE_ENABLE_STAT2,如果 SQLite 版本号介于 3.6.18 (2009-09-11) 和 3.7.8 (2011-09-19)。 sqlite_stat2表既不被任何人读取也不写入 3.6.18 之前的 SQLite 版本,以及 3.7.8 之后的版本。 sqlite_stat2表包含其他信息 关于索引中键的分布。 sqlite_stat2表的架构如下所示:

CREATE TABLE sqlite_stat2(tbl,idx,sampleno,sample);

每个列中的 sqlite_stat2.idx 列和 sqlite_stat2.tbl 列 sqlite_stat2 表的行标识该行描述的索引。 sqlite_stat2中通常有 10 行 每个索引的表。

具有 sqlite_stat2.sampleno 的索引的sqlite_stat2条目 0 和 9(含 0 和 9)是 索引沿索引均匀分布的点。 设 C 为索引中的行数。 然后,采样行由下式给出

行数 = (i*C*2 + C)/20

上一个表达式中的变量 i 在 0 和 9 之间变化。 从概念上讲,索引空间分为 10 个均匀的桶,样品是每个桶的中间一行。

此处记录了sqlite_stat2的格式,以供遗留参考。 最新版本的 SQLite 不再支持 sqlite_stat2 和 sqlite_stat2表(如果存在)将被忽略。

2.6.6. sqlite_stat3表

仅当编译 SQLite 时才使用sqlite_stat3 具有 SQLITE_ENABLE_STAT3 或 SQLITE_ENABLE_STAT4,并且 SQLite 版本号为 3.7.9 (2011-11-01) 或更高版本。 sqlite_stat3表既不被任何人读取也不写入 低于 3.7.9 的 SQLite 版本。 如果使用 SQLITE_ENABLE_STAT4 编译时选项,并且 SQLite 版本号为 3.8.1 (2013-10-17) 或更高版本, 然后sqlite_stat3可能会被读取但无法写入。 sqlite_stat3表包含其他信息 关于索引中键的分布,该信息 查询规划器可用于设计更好、更快的查询算法。 sqlite_stat3表的架构如下所示:

CREATE TABLE sqlite_stat3(tbl,idx,nEq,nLt,nDLt,sample);

每个索引的sqlite_stat3表中通常有多个条目。 sqlite_stat3.sample 列保存 由 sqlite_stat3.idx 和 sqlite_stat3.tbl 标识的索引。 sqlite_stat3.nEq 列包含近似值 索引中最左边列完全匹配的条目数 示例。 sqlite_stat3.nLt 保存 最左边列小于样本的索引。 sqlite_stat3.nDLt 列包含近似值 索引中小于 示例。

每个索引可以有任意数量的sqlite_stat3条目。 ANALYZE 命令通常会生成sqlite_stat3表 包含 10 到 40 个样本,分布在 键空间,并具有较大的 nEq 值。

在格式良好的sqlite_stat3表中,任何单个的样本 索引的显示顺序必须与它们在索引中的出现顺序相同。 换言之,如果最左边列 S1 的条目在 索引 b 树比 条目包含最左边的列 S2,然后在sqlite_stat3表中, 示例 S1 的 rowid 必须小于示例 S2。

2.6.7. sqlite_stat4表

仅创建sqlite_stat4,并且仅在编译 SQLite 时使用。 如果 SQLite 版本号为 SQLITE_ENABLE_STAT4,则为 3.8.1 (2013-10-17) 或更高版本。 sqlite_stat4表既不被任何人读取也不写入 3.8.1 之前的 SQLite 版本。 sqlite_stat4表包含其他信息 关于索引中键的分布或 WITHOUT ROWID 表的主键中的键。 查询规划器有时可以使用 sqlite_stat4表,用于设计更好、更快的查询算法。 sqlite_stat4表的架构如下所示:

CREATE TABLE sqlite_stat4(tbl,idx,nEq,nLt,nDLt,sample);

sqlite_stat4表中通常有 10 到 40 个条目 每个可用的统计数据索引,但这些限制是 不是硬性界限。 sqlite_stat4表中各列的含义如下:

结核病:sqlite_stat4.tbl 列包含 该行描述的索引
印尼达:sqlite_stat4.idx 列包含索引的名称,该索引 行描述,或者在 WITHOUT ROWID 表的sqlite_stat4条目, 表本身的名称。
样本:sqlite_stat4.sample 列包含 BLOB 以对索引列进行编码的记录格式,后跟 rowid 表的 rowid 或主键的列 对于 WITHOUT ROWID 表。 WITHOUT ROWID 表本身的 sqlite_stat4.sample BLOB 仅包含主键的列。 设 sqlite_stat4.sample blob 编码的列数为 N。 对于普通 rowid 表上的索引,N 将比数字多 1 索引的列数。 对于 WITHOUT ROWID 表上的索引,N 将是列数 indexed 加上主键中的列数。 对于 WITHOUT ROWID 表,N 将是 主键。
当量:sqlite_stat4.nEq 列包含 N 个整数的列表,其中 第 K 个整数是索引中条目的近似数 其最左边的 K 列与最左边的 K 列完全匹配 的样本。
nLt:sqlite_stat4.nLt 列包含 N 个整数的列表,其中 第 K 个整数是 其 K 个最左边列的总和 K 个样本最左边的列。
nDLt:sqlite_stat4.nDLt 列包含 N 个整数的列表,其中 第 K 个整数是近似值 索引中在前 K 列中不同的条目数,以及 其中最左边的 K 列总小于最左边的 K 列 样品的 K 列。

sqlite_stat4是sqlite_stat3表的概括。这 sqlite_stat3表提供有关 index,而 sqlite_stat4 表提供有关所有列的信息 的索引。

每个索引可以有任意数量的sqlite_stat4条目。 ANALYZE 命令通常会生成sqlite_stat4表 包含 10 到 40 个样本,分布在 键空间,并具有较大的 nEq 值。

在格式良好的sqlite_stat4表中,任何单个的样本 索引的显示顺序必须与它们在索引中的出现顺序相同。 换言之,如果条目 S1 在索引 b 树中早于 条目 S2,则在sqlite_stat4表中,示例 S1 必须具有 比样本 S2 小的 rowid。

3. 回滚日志

回滚日志是与每个 SQLite 数据库关联的文件 文件,用于将数据库文件还原到其初始 在事务过程中的状态。 回滚日志文件始终位于同一 目录作为数据库 文件,与数据库文件同名,但字符串 附加“-journal”。只能有一个回滚日志 与给定数据库相关联,因此只能有一次写入 一次针对单个数据库打开事务。

如果事务由于应用程序崩溃而中止,则操作 系统崩溃,或硬件电源故障或崩溃,则数据库可能 处于不一致的状态。下次SQLite尝试打开时 数据库文件,回滚日志文件的存在将是 检测到,日志将自动回放以恢复 数据库设置为未完成事务开始时的状态。

回滚日志仅在存在且 包含有效的标头。因此,事务可以在一个中提交 三种方式:

  1. 可以删除回滚日志文件,
  2. 回滚日志文件可以截断为零长度,或者
  3. 回滚日志的标头可以覆盖 无效的标题文本(例如,全零)。

这三种提交事务的方式对应于 DELETE, 分别对journal_mode编译指示进行 TRUNCAT 和 PERSIST 设置。

有效的回滚日志以下列格式的标题开头:

回滚日记帐标题格式

抵消大小描述
08标头字符串:0xd9、0xd5、0x05、0xf9、0x20、0xa1、0x63、0xd7
84“页数” - 下一段的页数 journal,或 -1 至 表示所有内容到文件末尾
124校验和的随机随机数
164数据库的初始大小(以页为单位)
204写入此内容的进程假定的磁盘扇区的大小 杂志。
244此日记中的页面大小。

回滚日志标题用零填充到 单个扇区(由偏移量 20 处的扇区大小整数定义)。 接头本身位于扇区中,因此如果发生断电,则 写入扇区,标题后面的信息将是 (希望)完好无损。

在页眉和零填充之后是零个或多个页面记录。每 页面记录存储数据库文件中页面内容的副本 在它被改变之前。同一页面可能不会出现多次 在单个回滚日志中。 要回滚未完成的事务,请执行流程 只需从头到尾阅读回滚日志,然后 将日志中的页面写回数据库文件中,网址为 适当的位置。

设数据库页面大小(偏移量为24处的整数值 在日志标题中)为 N。 那么页面记录的格式如下:

回滚日记页记录格式

抵消大小描述
04数据库文件中的页码
4N交易开始前页面的原始内容
N+44校验和

校验和是一个无符号的 32 位整数,计算方式如下:

  1. 将校验和初始化为在 偏移量 12 处的日记帐标题。
  2. 将索引 X 初始化为 N-200(其中 N 是数据库页的大小 以字节为单位。
  3. 将偏移量 X 处的字节解释为 8 位无符号整数 并将该整数的值添加到校验和中。
  4. 从 X 中减去 200。
  5. 如果 X 大于或等于零,请返回步骤 3。

校验和值用于防止不完整的写入 电源故障后的日记页记录。不同的随机随机数 每次启动交易时都会使用,以最大限度地降低风险 不成文的扇区可能偶然包含来自同一页面的数据 这是以前期刊的一部分。通过更改每个随机数 事务,磁盘上的陈旧数据仍将生成不正确的校验和 并且被高概率检测到。校验和仅使用稀疏样本 出于性能原因,数据记录中的 32 位字 - 设计研究 在 SQLite 3.0.0 的规划阶段显示 对整个页面进行校验和的性能显著降低。

让日记帐标题中偏移量 8 处的页数值为 M。 如果 M 大于零,则在 M 页记录日志文件之后 可能为零填充到扇区大小的下一个倍数和另一个 可以插入日志标题。所有日记帐标题都在同一 日志必须包含相同的数据库页面大小和扇区大小。

如果 M 在初始日记帐标题中为 -1,则页数记录 接下来是通过计算将容纳多少页记录来计算的 日志文件其余部分的可用空间。

4. 预写日志

从版本 3.7.0 (2010-07-21) 开始, SQLite支持新事务 称为“预写日志”或“WAL”的控制机制。 当数据库处于 WAL 模式时,与该数据库的所有连接都必须 使用 WAL.特定数据库将使用回滚日志 或 WAL,但不能同时使用两者。 WAL 始终与数据库位于同一目录中 文件,与数据库文件同名,但字符串 附加“-wal”。

4.1. WAL文件格式

WAL 文件由一个标头后跟零个或多个“帧”组成。 每一帧都记录了单页的修订内容 数据库文件。对数据库的所有更改都通过写入来记录 帧进入 WAL。当写入帧时,事务提交 包含提交标记。单个 WAL 可以而且通常确实记录 多个事务。定期,WAL 的内容是 在名为 “检查点”。

单个 WAL 文件可以多次重复使用。换言之, WAL 可以填满帧,然后进行检查点,然后是新的 帧可以覆盖旧帧。WAL 总是从一开始就成长 接近尾声。附加到每个帧的校验和和计数器是 用于确定 WAL 中的哪些帧有效以及哪些帧有效 是先前检查站的剩菜。

WAL 标头的大小为 32 个字节,由以下 8 个字节组成 big-endian 32 位无符号整数值:

WAL 标头格式

抵消大小描述
04幻数。0x377f0682或0x377f0683
44文件格式版本。目前为3007000。
84数据库页面大小。示例:1024
124检查点序列号
164Salt-1:随机整数随每个检查点递增
204Salt-2:每个检查点都有不同的随机数
244校验和-1:标头前 24 个字节的校验和的第一部分
284校验和-2:标头前 24 个字节的校验和的第二部分

紧跟在 wal-header 之后的是零帧或更多帧。每 Frame 由一个 24 字节的帧头和一个页面大小的字节组成 的页面数据。帧头是 6 个 big-endian 32 位无符号 整数值,如下所示:

WAL 帧头格式

抵消大小描述
04页码
44对于提交记录,数据库文件的大小(以页为单位) 提交后。对于所有其他记录,为零。
84从 WAL 标头复制的 Salt-1
124从 WAL 标头复制的 Salt-2
164校验和-1:累积校验和,包括此页
204校验和-2:累积校验和的后半部分。

当且仅当以下条件为 真:

  1. 帧头中的 salt-1 和 salt-2 值匹配 wal-header 中的 salt 值

  2. 帧标头最后 8 个字节中的校验和值 与连续计算的校验和完全匹配 WAL 标头的前 24 个字节和前 8 个字节,以及 所有帧的内容 直到并包括当前帧。

4.2. 校验和算法

校验和是通过将输入解释为 偶数个无符号 32 位整数:x(0) 到 x(N)。 如果 32 位整数是 big-endian,则 WAL 标头的前 4 个字节中的幻数为 0x377f0683,并且 如果幻数为 0x377f0682,则整数为 little-endian。 校验和值始终存储在帧标头中 big-endian 格式,无论使用哪个字节顺序进行计算 校验和。

校验和算法仅适用于 长度为 8 个字节。换句话说,如果输入是 x(0) 到 x(N) 那么 N 一定是奇数。 校验和算法如下:

s0 = s1 = 0
for i from 0 to n-1 step 2:s0 += x(i) + s1;s1 += x(i+1) + s0;
endfor
# result in s0 and s1

输出 s0 和 s1 都是使用斐波那契权重的加权校验和 以相反的顺序。(最大的斐波那契权重出现在第一个元素上 正在求和的序列。s1 值跨越所有 32 位整数 序列的项,而 s0 省略了最终项。

4.3. 检查点算法

在检查点上,首先使用 VFS 的 xSync 方法。 然后,将 WAL 的有效内容传输到数据库文件中。 最后,使用另一个数据库将数据库刷新到持久性存储 xSync 方法调用。 xSync 操作充当写入屏障 - 启动所有写入 在 xSync 必须完成之前,在 xSync 开始。

检查点无需运行即可完成。可能是一些 读取器仍在使用包含的数据的旧事务 在数据库文件中。在这种情况下,传输较新的内容 从 WAL 文件到数据库的事务将删除内容 从仍在使用旧事务的读者中走出来。为了避免这种情况, 只有当所有读者都使用 WAL 中的最后一笔交易。

4.4. WAL复位

在完成检查点后,如果事务中没有其他连接 使用 WAL,则后续写入事务可以 从头开始覆盖 WAL 文件。这称为“重置 沃尔“。在第一个新的开始 写入事务,WAL 标头 salt-1 值递增 并且 SALT-2 值是随机的。盐的这些变化使盐失效 WAL 中已检查但尚未检查的旧帧 覆盖,并防止它们再次被检查。

WAL 文件可以选择在重置时被截断,但不必如此。 如果 WAL 没有被截断,性能通常会好一点,因为 文件系统覆盖现有文件的速度通常比它们快 将增长一个文件。

4.5. 阅读器算法

要从数据库中读取页面(称为页码 P),阅读器 首先检查 WAL 以查看它是否包含页 P。如果是这样,那么 页 P 的最后一个有效实例,后跟提交帧 或者是提交帧本身成为读取的值。如果 WAL 不包含有效的页面 P 副本,并且是提交 frame 或后跟一个提交帧,然后从中读取第 P 页 数据库文件。

要启动读取事务,读取器记录值的数量 WAL 中的帧作为“mxFrame”。(更多详情) 读取器使用此记录的 mxFrame 值 对于所有后续读取操作。可以附加新交易 添加到 WAL,但只要读取器使用其原始 mxFrame 值 并忽略随后附加的内容,读者将看到一个 从单个时间点对数据库进行一致的快照。 此技术允许多个并发读取器查看不同的 同时版本的数据库内容。

前几段中的读取器算法工作正常,但是 因为页面 P 的框架可以出现在 WAL 中的任何位置,所以 读取器必须扫描整个 WAL 以查找第 P 页帧。如果 WAL 很大(通常为数兆字节),扫描速度可能很慢, 并且读取性能受到影响。为了克服这个问题,一个单独的 维护称为 wal-index 的数据结构以加快 搜索特定页面的框架。

4.6. WAL-Index 格式

从概念上讲,wal-index 是共享内存,尽管当前 VFS 实现使用内存映射文件作为操作系统 可移植性。内存映射 文件与数据库位于同一目录中,并具有相同的名称 作为附加了“-shm”后缀的数据库。因为 wal-index 是共享内存,当客户端位于不同的机器上时,SQLite 不支持网络文件系统上的 journal_mode=WAL,因为 数据库的所有客户端必须能够共享相同的内存。

wal-index 的目的是快速回答这个问题:

给定页码 P 和最大 WAL 帧索引 M, 返回不超过 M 的第 P 页的最大 WAL 帧索引, 或者,如果页面 P 没有不超过 M 的帧,则返回 NULL。

上一段中的 M 值是“mxFrame”值 在第 4.4 节中定义,在开头阅读 ,并定义来自 WAL 的最大帧 读者将使用。

wal 指数是瞬态的。崩溃后,wal-index 为 从原始 WAL 文件重建。VFS 是必需的 截断或将 wal-index 的标头归零,当最后一个 与它的连接关闭。因为wal指数是瞬态的,所以它可以 使用特定于体系结构的格式;它不一定是跨平台的。 因此,与存储所有值的数据库和 WAL 文件格式不同 作为大端,wal-index 将多字节值存储在本机中 主机的字节顺序。

本文档涉及数据库的持久状态 文件,并且由于 wal-index 是瞬态结构,因此无需进一步 有关 WAL 索引格式的信息将在此处提供。 有关 wal-index 格式的其他详细信息,请参见 单独的 WAL 索引文件格式文档。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/306141.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PVE系统的安装

一.PVE系统的安装 前置准备环境:windows电脑已安装Oracle VM VirtualBox,电脑支持虚拟化,且已经开启,按住ctrl+shift+ESC打开任务管理器查看是否开启,如果被禁用,可进入BIOS开启虚拟化,重启电脑后再进行后续操作。本步骤选用windows10安装VirtualBox,版本为7.0.8。 …

web安全-SSH私钥泄露

发现主机 netdiscover -r 192.168.164.0 扫描端口 看到开放80和31337端口都为http服务 浏览器访问测试 查看80端口和31337端口网页和源代码并无发现有用信息 目录扫描 扫描出80端口并无有用信息 扫描31337端口 发现敏感文件robots.txt和目录.ssh 访问敏感文件和目录 /.ss…

Ansys Zemax | 如何将光栅数据从Lumerical导入至OpticStudio(下)

附件下载 联系工作人员获取附件 本文介绍了一种使用Ansys Zemax OpticStudio和Lumerical RCWA在整个光学系统中精确仿真1D/2D光栅的静态工作流程。将首先简要介绍方法。然后解释有关如何建立系统的详细信息。 本篇内容将分为上下两部分&#xff0c;上部将首先简要介绍方法工作…

一键修复所有DLL缺失解决步骤,使用dll修复工具详情

在使用电脑或安装软件时&#xff0c;我们有时会遭遇DLL文件丢失的情况&#xff0c;这会阻止软件正常启动或运行。为此&#xff0c;一个简易且有效的解决方案是使用一键修复所有DLL缺失问题的工具。 引言 DLL&#xff08;动态链接库&#xff09;是Windows操作系统的核心部分&am…

k8s_入门_kubelet安装

安装 在大致了解了一些k8s的基本概念之后&#xff0c;我们实际部署一个k8s集群&#xff0c;做进一步的了解 1. 裸机安装 采用三台机器&#xff0c;一台机器为Master&#xff08;控制面板组件&#xff09;两台机器为Node&#xff08;工作节点&#xff09; 机器的准备有两种方式…

文库配置异步转换(宝塔)| 魔众文库系统

执行以下操作前提前进入网站根目录&#xff0c;如 cd /www/wwwroot/example.com执行 artisan 命令前请参照 开发教程 → 开发使用常见问题 → 如何运行 /www/server/php/xxx/bin/php artisan xxx 命令 步骤1&#xff0c;生成数据库队列表迁移文件 在执行该步骤前&#xff0c;请…

橘子学JDK之JMH-02(BenchmarkModes)

一、案例二代码 这次我们来搞一下官网文档的第二个案例&#xff0c;我删除了一些没用的注释&#xff0c;然后对代码做了一下注释的翻译&#xff0c;可以看一下意思。 package com.levi;import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.runner.Runner; import …

【科技】2024最新微信机器人一键部署教程

外话 话说上次写文章好像又过了几个月了…… 其实还是因为马上小升初的各种密考&#xff0c;其它地方不知道&#xff0c;反正广东这块名校基本上都得密考考进去 笔者连考几次都惨不忍睹…… 不过5月份会有一个信息技术特长生招生&#xff0c;看看能不能吧~ 正文 先说&#xff…

基于SpringBoot+Vue的高校大学生心理咨询管理系统(源码+文档+部署+讲解)

一.系统概述 系统根据现有的管理模块进行开发和扩展&#xff0c;采用面向对象的开发的思想和结构化的开发方法对高校大学生心理咨询管理的现状进行系统调查。采用结构化的分析设计&#xff0c;该方法要求结合一定的图表&#xff0c;在模块化的基础上进行系统的开发工作。在设计…

springboot相关报错解决

Caused by: java.lang.ClassNotFoundException: 目录 Caused by: java.lang.ClassNotFoundException: org.springframework.context.event.GenericApplicationListener spring-boot-dependencies:jar:2.1.9.RELEASE was not found org.springframework.context.event.Generi…

华为OD-C卷-攀登者1[100分]

攀登者喜欢寻找各种地图,并且尝试攀登到最高的山峰。 地图表示为一维数组,数组的索引代表水平位置,数组的元素代表相对海拔高度。其中数组元素0代表地面。 例如: [0,1,2,4,3,1,0,0,1,2,3,1,2,1,0],代表如下图所示的地图 地图中有两个山脉位置分别为 1,2,3,4,5 和 8,9,1…

SV-7042V 40W网络有源音柱 智慧灯杆广播音柱

SV-7042V 40W网络有源音柱 一、描述 SV-7042V是深圳锐科达电子有限公司的一款壁挂式网络有源音柱&#xff0c;具有10/100M以太网接口&#xff0c;可将网络音源通过自带的功放和喇叭输出播放&#xff0c;其采用防水设计&#xff0c;功率40W。 SV-7042V作为网络广播播放系统的终…

LongVLM:让大模型解读长视频 SOTA 的方法

LongVLM&#xff1a;让大模型解读长视频 SOTA 的方法 使用LongVLM处理长视频的步骤LongVLM 方法3.1 总体架构3.2 局部特征聚合3.3 全局语义整合 效果4.1 实验设置4.2 主要结果4.3 消融研究4.4 定性结果 论文&#xff1a;https://arxiv.org/pdf/2404.03384.pdf 代码&#xff1a…

C语言进阶课程学习记录-main函数与命令行参数

C语言进阶课程学习记录-main函数与命令行参数 main函数验证以下4中定义是否正确实验-main的返回值cmd窗口 实验-main的输入参数cmd窗口 在main函数执其执行的函数实验-程序执行的第一个函数gcc编译器cmd窗口bcc编译器 小结 本文学习自狄泰软件学院 唐佐林老师的 C语言进阶课程&…

SpringCloud Alibaba Sentinel 规则持久化

一、前言 接下来是开展一系列的 SpringCloud 的学习之旅&#xff0c;从传统的模块之间调用&#xff0c;一步步的升级为 SpringCloud 模块之间的调用&#xff0c;此篇文章为第十七篇&#xff0c;即使用 Sentinel 实现规则持久化。 二、概述 从前面我们做的实验可知&#xff0c;…

VsCode 安装Jupyter Notebook

VsCode 安装Jupyter Notebook 安装 1、打开 VSCode 编辑器&#xff0c;点击界面左端的【扩展】栏&#xff1b; 2、在【搜索框】中输入python&#xff0c;点击第一个Python&#xff0c;检查是否已经安装 python 插件&#xff0c;没安装的点击安装&#xff1b;已安装的继续第3步…

使用新版FLIR (FLIR_ADAS_v2) 数据集创建yolo格式数据集(目标检测)

FLIR在2022.1.19发布了新版的FLIR_ADAS_v2&#xff0c;有着更多的类别和数量更丰富的图像。数据集同步注释热图像和无注释RGB图像供参考。本文章主要介绍如何使用FLIR_ADAS_v2中的rgb图像和thermal图像来制作yolo格式数据集。 1.官方数据集下载&#xff1a;FLIR_ADAS_v2数据集…

【论文阅读——Profit Allocation for Federated Learning】

1.摘要 由于更为严格的数据管理法规&#xff0c;如《通用数据保护条例》&#xff08;GDPR&#xff09;&#xff0c;传统的机器学习服务生产模式正在转向联邦学习这一范式。联邦学习允许多个数据提供者在其本地保留数据的同时&#xff0c;协作训练一个共享模型。推动联邦学习实…

zotero+zotcard笔记美化(含模板)

首先感谢这篇文章和它的公众号&#xff0c;非常多关于zotero教程干货Zotero笔记样式美化 (qq.com) 效果 zotcard信息卡 <h1>&#x1f4dc;<strong>信息卡</strong></h1> <ul><li>&#x1f42c;<span style"color: #005EFF"&g…

自定义集合类实现接口IEnumrable和IEnumrator,遍历/迭代自定义集合对象

先来说说IEnumrable和IEnumrator接口&#xff0c;IEnumrable接口成员如下&#xff1a; public interface IEnumerable { IEnumerator GetEnumerator(); } IEnumrable是可枚举类型&#xff0c;什么是可枚举类型呢&#xff1f;简单说&#xff0c;就是实现了I…