ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

SQLite JSONB 二进制格式详解:结构、编码原理与源码实现(SQLCipher 仓库解析)

SQLite JSONB 二进制格式详解:结构、编码原理与源码实现(SQLCipher 仓库解析) 数据库关系型数据库嵌入式数据库密码学【免费下载链接】sqlcipherSQLCipher is a standalone fork of SQLite that adds 256 bit AES encryption of database files and other security features.项目地址https://gitcode.com/gh_mirrors/sq/sqlcipher点击查看免费下载导读本文以仓库中的官方格式规范文档 doc/jsonb.md 为主体深入讲解 SQLite当前仓库版本 3.53.4见 VERSION自 3.45.0 起引入的 JSONB 二进制 JSON 编码它如何以 BLOB 形式存储 JSON、头部header如何同时编码元素类型与负载大小、16 种元素类型码的语义、以及惰性转换设计背后的性能动机。读完本文你将能读懂任意 JSONB 字节流的二进制布局理解jsonb()等内置函数对 JSONB 的处理链路并能在实际项目中正确使用与验证 JSONB。文中所有结论均以仓库文档、源码 src/json.c 与测试用例 test/jsonb01.test 相互印证。1.0 什么是 JSONB根据 doc/jsonb.md 的定义从 SQLite 3.45.0约 2024-01-01开始SQLite 支持一种 JSON 的替代二进制编码称为JSONB。JSONB 是一种以BLOB形式存储的二进制格式。相比普通的 RFC 8259 文本 JSONJSONB 的优势有两个体积更小大多数情况下比文本 JSON 小 5%10%处理更快消耗的 CPU 周期通常不到文本 JSON 的一半。SQLite 内置的 JSON SQL 函数 对于任何 JSON 输入既可以接受普通文本 JSON也可以接受二进制 JSONB 编码两者对调用方透明。关于命名文档明确指出JSONB 名称受 PostgreSQL 启发但 SQLite 的 JSONB 磁盘格式与 PostgreSQL 完全不同——两者同名内部表示却截然不同二进制层面完全不兼容。JSONB 的核心设计思想是每个元素以头部header开始头部包含该元素的大小和类型。头部取代了文本 JSON 中的双引号、花括号、方括号、逗号、冒号等标点符号。由于每个元素的大小和类型都已记录在头部解析时无需再向前扫描寻找闭合分隔符读取因此更快。JSONB 的负载payload与对应文本 JSON 相同相同的负载字节以相同顺序出现唯一实质区别是 JSONB 为每个元素增加二进制头部并省略分隔与标点符号。1.1 仅供内部使用格式细节并不打算对应用开发者可见。应用开发者应当将 JSONB 视为 SQLite 内部使用的不透明 BLOB。尽管如此SQLite 希望该格式在所有未来版本中保持向后兼容因此格式规范以本文档形式保存在源码树中本文档仅供 SQLite 核心开发者使用而不是供只使用 SQLite 的应用开发者使用。2.0 本文档的目的JSONB 不是供应用使用的外部格式而是为 SQLite 内部使用而设计。程序员无需理解 JSONB 格式也能有效使用它。应用应当只通过 JSON SQL 函数访问 JSONB而不是直接查看 BLOB 的单个字节。然而JSONB 必须可移植并在所有未来版本中向后兼容——也就是说升级到更新的 SQLite 版本时不应需要导出并重新导入数据库文件。因此JSONB 格式必须被精确定义。本文档的目的与 SQLite 数据库文件格式 文档描述 SQLite 数据库文件磁盘格式的文档本仓库中的同类格式文档还包括 doc/pager-invariants.txt、doc/vfs-shm.txt 等相似应用不被期望直接读写数据库文件的比特与字节但格式仍被仔细记录以保证其稳定与持久。JSONB 的表示同样在此被记录目的是稳定持久而非让应用读写单个字节。3.0 编码JSONB 是底层文本 JSON 的直接翻译。区别在于 JSONB 使用比文本 JSON 详细语法更快解析的二进制编码。每个 JSON 元素编码为一个头部header加一个负载payload头部决定元素类型字符串、数字、布尔、null、对象或数组以及负载大小头部大小为 19 字节负载大小可从 0 字节到允许的最大 BLOB 大小。3.1 负载大小编码头部第一个字节的高四位决定头部大小并可能同时决定负载大小高四位值头部总大小负载大小如何确定011恰好 1 字节负载大小由这高四位本身直接给出122 字节负载大小为后续 1 字节的无符号大端整数133 字节负载大小为后续 2 字节的无符号大端整数145 字节负载大小为后续 4 字节的无符号大端整数159 字节负载大小为后续 8 字节的无符号大端整数当前 SQLite 的设计不支持大于 2GiB 的 BLOB 值因此8 字节变体永远不会被当前代码使用。8 字节负载大小整数被包含在规范中仅用于允许未来扩展。头部不需要是其最简形式。文档以 JSON 数字值1为例说明该元素可以有五种不同的编码方式0x13 0x31 0xc3 0x01 0x31 0xd3 0x00 0x01 0x31 0xe3 0x00 0x00 0x00 0x01 0x31 0xf3 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x31其中0x13高四位为 1负载长度 1 字节低四位为 3类型 INT随后是负载0x31ASCII 字符1后面四种分别用 1、2、4、8 字节的大端长度字段声明负载大小为 1并补零。最短编码当然更受青睐通常出现在数字等原始元素上。然而数组或对象的总大小在生成其头部时可能尚未精确得知——方便的做法是先为最大可能的头部预留空间最后再回头填上正确的负载大小。这种技术可能导致数组或对象头部比绝对必要更大。这正是 src/json.c 中jsonBlobAppendNode()的实现逻辑编码时根据负载大小选择 1/2/3/5 字节的头部形态也印证了先预留、后回填的机制见同文件jsonBlobChangePayloadSize()src/json.c。3.2 元素类型头部第一个字节的低四位即该字节与0x0f求与决定元素类型。当前使用以下代码低四位值类型名含义0NULLJSONnull。真正的 JSON null 负载大小必须为 0未来版本可能用类型 0 但非零负载大小的元素做扩展旧版本会将其解释为 NULL 以保持向后兼容1TRUEJSONtrue。真正的true负载大小必须为 0类型 1 且非零负载大小保留给未来扩展旧实现应继续按true解释2FALSEJSONfalse。真正的false负载大小必须为 0类型 2 且非零负载大小保留给未来扩展旧实现应继续按false解释3INT规范 RFC 8259 格式的 JSON 整数值无扩展。负载是该数值的 ASCII 文本表示4INT5十六进制记法的 JSON 整数字面量。负载是该字面量的 ASCII 文本表示。因负载是非标准格式转为 RFC 8259 文本 JSON 时需翻译5FLOAT规范 RFC 8259 格式的 JSON 浮点值无扩展。负载是该数值的 ASCII 文本表示6FLOAT5非规范 JSON 格式、而是扩展 JSON5 格式的浮点值。负载是 ASCII 文本表示转为 RFC 8259 文本 JSON 时需翻译7TEXT不含任何转义、也不含需要为 SQL 或 JSON 转义字符的 JSON 字符串。负载是该字符串值的 UTF8 文本表示不含字符串定界符8TEXTJ含 RFC 8259 字符转义如\n或\u0020的 JSON 字符串。若该元素被json_extract提取到 SQL 中这些转义需翻译为实际 UTF8。负载是转义后字符串的 UTF8 表示不含定界符9TEXT5含字符转义包括 JSON5 特有、RFC 8259 规范中没有的转义的 JSON 字符串。渲染为文本前需翻译为标准 JSON或提取到 SQL 时翻译为实际 UTF8 字符。负载是 UTF8 表示不含定界符10TEXTRAW含 UTF8 字符、且渲染为标准 JSON 文本时需要转义的 JSON 字符串。负载不含定界符11ARRAYJSON 数组。负载包含构成数组值的 JSONB 元素12OBJECTJSON 对象。负载包含构成对象条目的成对 JSONB 元素。每对第一个元素必须是字符串类型 710每对第二个元素可以是任意类型包括嵌套数组或对象13RESERVED-13保留给未来扩展。旧实现遇到应报错14RESERVED-14保留给未来扩展。旧实现遇到应报错15RESERVED-15保留给未来扩展。旧实现遇到应报错范围 012 之外的元素类型均保留给未来扩展。当前实现遇到上述列表之外的元素类型会报错不过未来版本可能利用剩余三种类型实现索引或类似优化以加速对大型 JSON 数组/对象的查找。这些类型常量在源码中有精确对应。见 src/json.c#define JSONB_NULL 0 /* null */ #define JSONB_TRUE 1 /* true */ #define JSONB_FALSE 2 /* false */ #define JSONB_INT 3 /* integer acceptable to JSON and SQL */ #define JSONB_INT5 4 /* integer in 0x000 notation */ #define JSONB_FLOAT 5 /* float acceptable to JSON and SQL */ #define JSONB_FLOAT5 6 /* float with JSON5 extensions */ #define JSONB_TEXT 7 /* Text compatible with both JSON and SQL */ #define JSONB_TEXTJ 8 /* Text with JSON escapes */ #define JSONB_TEXT5 9 /* Text with JSON-5 escape */ #define JSONB_TEXTRAW 10 /* SQL text that needs escaping for JSON */ #define JSONB_ARRAY 11 /* An array */ #define JSONB_OBJECT 12 /* An object */3.3 元素类型的设计动机JSONB 的一个关键目标是能快速地在文本 JSON 与 JSONB 之间互转或从 SQL 值直接构建。从文本转换为 JSONB 时不希望转换子程序把 CPU 周期浪费在把元素值转成某种可能永远用不上的标准格式上——格式转换是**惰性lazy**的即推迟到真正需要时才执行。这带来两个格式设计推论数值以文本而非数字形式存储且是其来源文本 JSON 值的直接拷贝存在多个按值格式细节区分的元素类型。例如 INT 用于纯 RFC-8259 整数字面量INT5 用于十六进制记法等 JSON5 扩展FLOAT 用于纯 RFC-8259 浮点字面量FLOAT5 用于 JSON5 扩展字符串则有四种表示取决于字符串来源以及其中特殊字符的转义方式。JSONB 的第二个目标是能够充当 SQLite 内置 JSON SQL 函数处理 JSON 时的解析树parse tree。在 JSONB 出现之前json_replace()、json_patch()等操作分三步进行将文本 JSON 翻译成更易扫描和编辑的内部格式对 JSON 执行请求的操作将内部格式翻译回文本。JSONB 试图直接充当内部格式跳过第 1 和第 3 步。由于大部分 CPU 周期都消耗在第 1 和第 3 步上因此 JSONB 的处理会比文本 JSON 快得多——这与文档第 1.0 节不到一半 CPU 周期的论断相互印证。处理 JSONB 时只需第 2 步而处理文本 JSON 时仍需要第 1 和第 3 步。既然 JSONB 要做内部二进制表示这又成为数值以文本存储的另一个理由以文本存数可最小化第 1、3 步所需的转换工作。四种文本表示同理不同文本表示服务于不同来源RFC-8259 JSON、JSON5 或 SQL 字符串值转换只在确实需要时才发生。3.4 合法的 JSONB BLOB一个合法的 JSONB BLOB 由单个 JSON 元素组成且该元素必须恰好填满整个 BLOB。这个唯一元素通常是 JSON 对象或数组其负载通常包含更多元素但也可以是字符串、数字、布尔或 null 等原始值。当内置 JSON 函数试图判断一个 BLOB 参数是 JSONB 还是随机 BLOB 时它们会查看最外层元素的头部检查其是否格式良好、且该元素是否完整填满 BLOB。若满足这些条件该 BLOB 即被接受为 JSONB 值。这一判断逻辑在源码中体现为jsonArgIsJsonb()src/json.c其关键条件包括参数必须是 SQL BLOB 类型sqlite3_value_type(pArg)!SQLITE_BLOB直接返回 0首字节低四位(c 0x0f)必须小于等于JSONB_OBJECT通过jsonbPayloadSize()解析出的头部负载总长度必须恰好等于 BLOB 总长度sznp-nBlob对 null/true/false 要求负载大小为 0(c 0x0f)JSONB_FALSE || sz0对体积较小的 BLOB还需进一步执行jsonbValidityCheck()完整校验内部结构。jsonbPayloadSize()src/json.c则正是 3.1 节所描述的头部长度/负载大小解码器高四位x11时 1 字节头、x12时 2 字节、x13时 3 字节、x14时 5 字节、否则 9 字节并逐级做越界检查。4.0 在 SQL 中使用 JSONB应用开发者无需理解字节级格式只需通过 SQL 函数使用 JSONB。4.1 把文本 JSON 转为 JSONBjsonb()与jsonb_*函数族SQLite 内置了完整的jsonb_*函数族与对应的json_*函数一一配对。从 src/json.c 的函数注册表可见完整的对应关系文本版函数JSONB 版函数json()jsonb()json_array()jsonb_array()json_array_insert()jsonb_array_insert()json_extract()jsonb_extract()json_insert()jsonb_insert()json_object()jsonb_object()json_patch()jsonb_patch()json_remove()jsonb_remove()json_replace()jsonb_replace()json_set()jsonb_set()json_group_array()聚合jsonb_group_array()聚合json_group_object()聚合jsonb_group_object()聚合注意json_extract的-与-运算符同样可用-返回 JSON可能为 JSONB-返回 SQL 文本。聚合函数jsonb_group_array/jsonb_group_object在注册时带有JSON_BLOB标志src/json.c直接以 BLOB 输出格式生成 JSONB。此外还有表值函数jsonb_each与jsonb_tree与json_each/json_tree对应见 src/json.c 的模块注册表。4.2 声明 JSONB 类型的列test/jsonb01.test 展示了典型用法——用JSON BLOB声明列类型并写入 JSONBCREATE TABLE t1(x JSON BLOB); INSERT INTO t1 VALUES(jsonb({a:5,b:{x:10,y:11},c:[1,2,3,4]}));随后可直接对 JSONB 列执行jsonb_remove(x,$path)、json_remove(x,$path)等操作两种函数返回一致结果见测试用例jsonb01-1.2.*。4.3 把 JSONB 渲染回文本json()函数json()函数可将 JSONB 渲染为标准文本 JSON。在源码中从二进制到文本的转换由jsonTranslateBlobToText()src/json.c实现逐元素读取头部类型按JSONB_NULL/TRUE/FALSE/INT/FLOAT/TEXT/TEXTJ/TEXT5/TEXTRAW/ARRAY/OBJECT分别渲染src/json.c其中INT5/FLOAT5/TEXT5等非标准表示会在此翻译为规范 JSON。测试 test/jsonb01.test 还覆盖了畸形 JSONB 的拒绝路径对含有非法 FLOAT5 的 BLOB 调用json()会返回malformed JSON错误——这正是jsonArgIsJsonb()与jsonbValidityCheck()校验链路的验证。5.0 性能验证与测试仓库中提供了专门的性能测试流程文档见 test/json/README.md。该流程用tclsh json-generator.tcl生成约 100MB 的测试库json100mb.db再复制出jsonb100mb.db并在 sqlite3 命令行 shell 中用UPDATE data1 SET xjsonb(x);把全部文本 JSON 转成 JSONB随后分别运行sh json-speed-check.sh trunk # 文本 JSON 基线 sh json-speed-check.sh trunk --jsonb # JSONB 性能分析通过对比两次 profile 输出jout-trunk.txt与joutb-trunk.txt可以实测文档所述JSONB 处理快于文本 JSON、且体积更小的结论。JSONB 的单元测试集中在 test/jsonb01.test 中覆盖创建 JSONB 列、写入jsonb()转换结果用例jsonb01-1.1对 JSONB 执行jsonb_remove与json_remove验证$.a、$.b.x、$.c[0]、$.c[#-1]等各类路径用例jsonb01-1.2.*拒绝畸形 JSONB用例jsonb01-2.0、jsonb01-3.0。6.0 关键要点速查JSONB 是 SQLite 3.45.0 的二进制 JSON 编码以 BLOB 存储比文本 JSON 小 5%10%处理 CPU 周期不足一半每个元素 头部19 字节 负载头部首字节高四位编码头部/负载大小低四位编码元素类型015当前用 0121315 保留负载与文本 JSON 的字节相同、顺序相同只少了定界与标点符号数值以 ASCII 文本存储惰性转换字符串有 TEXT/TEXTJ/TEXT5/TEXTRAW 四种形态INT5/FLOAT5 承载 JSON5 扩展合法 JSONB BLOB 单个元素恰好填满 BLOB由jsonArgIsJsonb()src/json.c判定应用只应通过jsonb()、jsonb_extract、jsonb_set、jsonb_each等内置函数访问 JSONB不要直接解析字节格式规范 doc/jsonb.md 仅供 SQLite 核心开发者维护兼容性使用与 PostgreSQL 的 JSONB 同名但二进制不兼容不可混用。7.0 延伸阅读格式与实现相关文件均在当前仓库内格式规范正文doc/jsonb.md本文所依据的主体文档JSON 函数与 JSONB 编解码实现src/json.c类型常量 L125-L137、头部编码 L1243-L1280、负载大小解码 L2123-L2177、JSONB 判定 L3621-L3642、函数注册表 L5656-L5717功能测试test/jsonb01.test性能对比测试流程test/json/README.md相关增强说明doc/json-enhancements.md赞分享数据库关系型数据库嵌入式数据库密码学【免费下载链接】sqlcipherSQLCipher is a standalone fork of SQLite that adds 256 bit AES encryption of database files and other security features.项目地址https://gitcode.com/gh_mirrors/sq/sqlcipher点击查看免费下载相关推荐SQLite JSONB 二进制格式完全解析从头部编码到源码实现SQLite JSONB 二进制格式完全解析从头部编码到源码实现 JSONB 是 SQLite 从 3.45.0 版本约 2024 01 01开始引入的一数据库关系型数据库嵌入式数据库SQLite中的JSONB二进制格式解析SQLite中的JSONB二进制格式解析 概述 SQLite从3.45.0版本 约2024年1月发布 开始引入了一种称为JSONB的JSON二进制编码格式。JS数据库关系型数据库嵌入式数据库用 stock 仓库的 3 个模块和 2 个默认值把组合权重从 Excel 里算出来用 stock 仓库的 3 个模块和 2 个默认值把组合权重从 Excel 里算出来 手动调仓最大的麻烦是顾此失彼刚把一只基金调重另一只就被稀释了最后持金融科技数据分析机器学习创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表