PgSQL · 特性分析· jsonb类型解析

本文详细介绍了PostgreSQL 9.4版本中新增的jsonb数据类型,包括其内部存储机制、如何创建jsonb类型的表及GIN索引,并对比了jsonb与之前的json类型的不同之处。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

PG 9.4版本里面,增强了对json数据的支持,受到了很大关注。9.4之前,PG已经原生支持json数据类型了,但只是用字符串的形式存储和处理。这样做天然有性能上的缺点:每次对json字符串里面的数据进行查询,一般需要全表扫描加字符串匹配,效率很低。当然也可以在存储json的字符串字段上创建GIN索引,但需要对查询中用到的json的key或value创建单独索引,造成要被动维护很多索引。所以,这种json类型,只适用于把PG单纯作为数据存储,只读入读出数据,不对数据进行限定key或value查询的场景。

PG 9.4中引入了jsonb类型。其特点是,将json数据中的key和value进行解析,转换为PG的基本数据类型,包括数字,字符串和布尔类型等;同时,增加了对应的GIN处理函数,可以将json中的所有key和value转换为GIN索引的key。这样,只用一个GIN索引,即可实现对所有key或value的条件查询。下面我们分析一下jsonb的使用方法和内核实现。

使用

创建含jsonb类型的表方法如下所示:


创建GIN索引的方法如下:


可以使用下面的查询得到含有<product, ProgreSQL>键值对的行:



内核实现

先分析一下jsonb是如何从字符串,变成特殊的二进制形式存入磁盘的。追踪一下jsonb插入的过程,可以看到PG所调用的函数流程如下。


其中,pg_parse_json先把用户输入的字符串,通过编译器转换为一个树形结构(每个节点的类型为JsonbValue)。然后JsonbValueToJsonb在这个结构基础上,转换为存入磁盘的格式。从convertJsonbObject函数可以看出,转换为磁盘格式的策略为:从树形结构的根部开始遍历,递归进行广度优先遍历。对于同一父亲下面的子键值,将所有键名(字符串)长度写入buffer中预留的头部,随后将键名依次写入buffer中。最后再以相似的方式写入键所对应的所有值(值如果是json对象,则递归调用)。这样,读入buffer的头部,就可以遍历出所有键名的位置,得到键名。再从读第一个键值开始,读入对应的值或子键,最终得到整个树(见JsonbIteratorNext)。

采用这种存储方式,jsonb所占用的存储空间比原来支持的json类型要多一些。其实,jsonb的核心优势在于快速和灵活的索引。从前面创建index的语句可以看到,jsonb支持两种特有的GIN索引jsonb_ops和jsonb_path_ops。我们知道,GIN索引建立时,会先通过内建函数从表中每行数据的索引字段的值中,抽取键(key),一个字段值一般可抽取多个key。然后,将每个key与含有此key的所有行的ID组成键值对,再将它们插入b树索引供查询。那么这两种GIN索引有什么区别呢?

它们的区别在于,生成GIN key的方式不同。jsonb_ops调用gin_extract_jsonb函数生成key,这样每个字段的json数据中的所有键和值都被转成GIN的key;而jsonb_path_ops使用函数gin_extract_jsonb_path抽取:如果将一个jsonb类型的字段值看做一颗树,叶子节点为具体的值,中间节点为键,则抽取的每个键值实际上时每个从根节点到叶子节点的路径对应的hash值。

不难推测,jsonb_path_ops索引的key的数目和jsonb的叶子节点数有关,用叶子节点的路径做查询条件时会比较快(这也是这种索引唯一支持的查询方式);而jsonb_ops索引的key的数目与jsonb包含的键和值(即树形结构的所有节点)的总数有关,可以用于路径查询之外的其他查询。


<think>好的,我现在需要回答用户关于Oracle和PostgreSQL区别的问题。首先,用户之前询问了MySQL的面试题,现在转向比较两个不同的数据库系统,Oracle和PostgreSQL。这说明用户可能在准备数据库相关的面试,或者希望了解不同数据库的特点以便选择合适的技术栈。 首先,我需要回顾自己关于Oracle和PostgreSQL的知识。Oracle是一个商业的关系型数据库管理系统,广泛应用于企业级应用,以高性能、高可用性和强大的功能著称。PostgreSQL则是开源的对象关系型数据库,强调标准兼容性和扩展性,支持复杂查询和多种数据类型。 用户可能想知道这两个数据库的主要区别,包括许可和成本、功能特性、性能、生态系统等方面的对比。同时,用户可能关注它们在事务处理、并发控制、扩展性、高可用性解决方案等方面的差异。此外,作为面试准备,用户可能希望了解在实际应用场景中的选择考量,比如企业级应用更适合Oracle,而初创公司或需要灵活性的项目可能倾向PostgreSQL。 接下来需要组织回答的结构。通常,对比类的问题可以分点列出,每个点涵盖一个方面,比如许可成本、功能特性、性能、扩展性、高可用性、生态系统等。同时,给出实际应用场景的建议,帮助用户理解如何选择。 需要注意的是,要确保信息准确,比如Oracle的许可费用确实较高,而PostgreSQL是开源的。此外,提到Oracle的优化器高级特性,如自适应查询优化,而PostgreSQL支持JSONB和GIS扩展等。还要提到两者在事务隔离级别、复制机制等方面的不同。 可能还需要指出两者在某些方面的相似性,比如都支持ACID事务,但实现方式可能不同。比如Oracle使用多版本并发控制(MVCC)和回滚段,而PostgreSQL也使用MVCC,但实现机制不同,可能导致性能差异。 另外,用户可能对扩展性和定制化感兴趣,PostgreSQL的扩展性较好,支持多种插件,而Oracle虽然功能强大,但定制化可能需要更高的成本。 还需要考虑用户可能的后续问题,比如迁移成本、学习曲线等,但当前问题主要聚焦在区别上,所以回答应集中在主要区别点上。 最后,总结两者的适用场景,帮助用户根据需求做出选择。例如,大型企业需要高可靠性和支持服务,可能选择Oracle;预算有限且需要灵活性的项目可能选择PostgreSQL。 在回答过程中,要注意用词准确,避免技术错误,比如正确描述两者的MVCC实现差异,或者分区表的不同处理方式。同时,使用用户易懂的语言,避免过于专业的术语,必要时进行解释。 现在,我需要验证一些信息,比如PostgreSQL的JSONB类型确实优于Oracle的JSON支持,Oracle的RAC集群是否还是主要的高可用解决方案,以及PostgreSQL的流复制和逻辑复制的特点。同时,确认Oracle的分区表功能是否在最新版本中有改进,以及PostgreSQL的分区表实现方式。 此外,需要检查是否存在过时的信息,例如Oracle的最新版本是否引入了更多开源特性,或者PostgreSQL在某些性能方面是否有了提升。确保提供的信息是基于当前最新的稳定版本。 总结来说,回答应该结构清晰,分点对比,涵盖用户关心的主要方面,并提供实际应用的建议,确保内容准确且易于理解。</think>以下是 Oracle 和 PostgreSQL 的核心区别对比,从架构设计、功能特性到适用场景的全面解析: --- ### **一、基础定位对比** | **维度** | **Oracle** | **PostgreSQL** | |-----------------|--------------------------------|--------------------------------| | **类型** | 商业数据库(闭源) | 开源数据库(BSD协议) | | **开发目标** | 企业级高可靠、高并发场景 | 强调标准兼容性扩展性 | | **典型用户** | 金融、电信等大型企业 | 互联网企业、初创公司、GIS领域 | --- ### **二、核心特性差异** #### **1. 事务并发控制** - **Oracle** - 使用 **UNDO 段** + **多版本并发控制 (MVCC)** - 默认隔离级别:**读已提交 (Read Committed)** - 支持 **Flashback Query**(数据闪回) - **PostgreSQL** - 纯 **MVCC 实现**(无UNDO段,通过可见性规则控制) - 默认隔离级别:**读已提交 (Read Committed)**,但 **可重复读 (Repeatable Read)** 无幻读(通过快照隔离) - 支持 **事务嵌套**(通过SAVEPOINT) #### **2. 数据类型扩展** - **Oracle** - 内置 **XMLType**、**JSON**(12c+) - 支持 **LOB**(大对象存储) - 提供 **VARCHAR2**(最大32KB)和 **CLOB** - **PostgreSQL** - 原生支持 **JSONB**(二进制存储,高效查询) - 丰富扩展类型:**数组**、**HStore**(键值对)、**GIS地理数据**(PostGIS) - 自定义类型:CREATE TYPE 支持复合类型 #### **3. 分区分片** - **Oracle** - **分区表**(Range/List/Hash/Composite) - **Sharding**(需额外购买选项,基于全局目录) - 支持 **自动分区**(Interval Partitioning) - **PostgreSQL** - **声明式分区**(11+版本原生支持) - 通过 **FDW(外部数据包装器)** 实现分片 - 社区方案:**Citus**(分布式扩展) --- ### **三、性能优化** #### **1. 查询优化器** - **Oracle** - **CBO(基于成本优化器)** 高度成熟 - 自适应执行计划(12c+ 动态调整) - 提供 **SQL Plan Management**(计划稳定性控制) - **PostgreSQL** - **CBO** 较完善,但对复杂查询优化有限 - 支持 **并行查询**(9.6+) - 依赖 **扩展统计信息**(CREATE STATISTICS) #### **2. 索引类型** | **索引类型** | Oracle 支持 | PostgreSQL 支持 | |------------------|---------------------------|------------------------------| | B-Tree | ✔️ | ✔️ | | 位图索引 | ✔️(OLAP场景) | 通过扩展实现 | | 全文检索 | Oracle Text | TSVector/TSQuery | | 空间索引 | Spatial | GIST/GIN(PostGIS扩展) | | 函数索引 | ✔️ | ✔️ | --- ### **四、高可用容灾** #### **1. Oracle 方案** - **Data Guard**:物理/逻辑备库(最大保护模式) - **RAC(实时应用集群)**:多节点共享存储(需ASM) - **GoldenGate**:跨平台数据同步 #### **2. PostgreSQL 方案** - **流复制**:异步/同步物理复制(WAL日志同步) - **逻辑复制**(10+):表级数据同步 - **Patroni** + **etcd**:自动化故障切换 - **PgPool-II**:连接池负载均衡 --- ### **五、开发管理** #### **1. SQL 方言差异** ```sql -- 分页查询 -- Oracle SELECT * FROM (SELECT t.*, ROWNUM rn FROM table t) WHERE rn BETWEEN 11 AND 20; -- PostgreSQL SELECT * FROM table LIMIT 10 OFFSET 10; -- 时间处理 -- Oracle SELECT SYSDATE FROM DUAL; -- PostgreSQL SELECT NOW(); ``` #### **2. 存储过程** - **Oracle**:PL/SQL(强类型,紧密集成) - **PostgreSQL**:PL/pgSQL(类似PL/SQL),支持 Python/Perl 等语言扩展 --- ### **六、成本生态系统** | **维度** | **Oracle** | **PostgreSQL** | |-----------------|--------------------------------|--------------------------------| | **许可费用** | 高昂(按CPU核心计费) | 免费(商业支持可选) | | **工具链** | Enterprise Manager、SQL Developer | pgAdmin、DBeaver、Metabase | | **云支持** | Oracle Cloud 深度集成 | AWS RDS/Aurora、Azure DB等主流云 | --- ### **七、选型建议** - **选择 Oracle 的场景**: - 需要企业级 SLA 支持 - 处理超高并发 OLTP(如银行核心系统) - 已有大量 Oracle 历史资产 - **选择 PostgreSQL 的场景**: - 需要高度定制化(如扩展数据类型) - 预算有限但需强事务支持 - GIS 地理数据处理(配合 PostGIS) --- **补充说明**:近年来 PostgreSQL 在企业级特性(如并行查询、JIT编译)快速演进,而 Oracle 也在拥抱云原生(Autonomous Database)。实际选型需结合 **团队技术栈** + **业务规模** + **长期成本** 综合评估。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值