「Postgresql架构」使用PostgreSQL中的JSONB数据类型加快操作

本文涉及的产品
云原生数据库 PolarDB MySQL 版,通用型 2核4GB 50GB
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
简介: 「Postgresql架构」使用PostgreSQL中的JSONB数据类型加快操作

从版本9.4开始,PostgreSQL在使用JSON数据的二进制表示jsonb时提供了显着的加速,这可以为您提供增加性能所需的额外优势。

什么是jsonb

由PostgreSQL文档定义的数据类型json和jsonb几乎相同;关键的区别在于json数据存储为JSON输入文本的精确副本,而jsonb以分解的二进制形式存储数据;也就是说,不是ASCII / UTF-8字符串,而是二进制代码。

这有一些直接的好处:

  1. 效率更高,
  2. 加工速度明显加快
  3. 支持索引(这可能是一个重要的优势,我们稍后会看到),
  4. 更简单的模式设计(用jsonb列替换实体 - 属性 - 值(EAV)表,可以查询,索引和连接,从而使性能提高到1000倍!)

还有一些缺点:

  1. 输入稍慢(由于增加的转换开销),
  2. 它可能需要比普通json更多的磁盘空间,因为更大的表占用空间,尽管并非总是如此,
  3. 由于缺乏统计信息,某些查询(尤其是聚合查询)可能会变慢。

最后一个问题背后的原因是,对于任何给定的列,PostgreSQL保存描述性统计信息,例如不同和最常见值的数量,NULL条目的分数,以及 - 对于有序类型 - 数据分布的直方图。当信息作为JSON字段输入时,所有这些都将不可用,并且您将遭受严重的性能损失,尤其是在大量JSON字段之间聚合数据(COUNT,AVG,SUM等)时。

为避免这种情况,您可以考虑存储稍后可能在常规字段上汇总的数据。

有关此问题的进一步评论,您可以阅读Heap的博客文章何时在PostgreSQL架构中避免使用JSONB。

用例:书籍条目

让我们使用带有书籍条目的玩具模型来说明在PostgreSQL中使用JSON数据时的一些基本操作。

如果您使用json或jsonb,本节中的操作将基本相同,但让我们回顾它们以刷新我们可以用JSON做什么,并在我们看到jsonb好吃之后立即设置我们的用例。

在表中定义列

很简单,我们使用jsonb数据类型指定数据列:

CREATE TABLE books ( book_id serial NOT NULL, data jsonb );

插入JSON数据

要将数据输入books表,我们只需将整个JSON字符串作为字段值传递:

INSERT INTO books VALUES (1, '{"title": "Sleeping Beauties", "genres": ["Fiction", "Thriller", "Horror"], "published": false}');
INSERT INTO books VALUES (2, '{"title": "Influence", "genres": ["Marketing & Sales", "Self-Help ", "Psychology"], "published": true}');
INSERT INTO books VALUES (3, '{"title": "The Dictator''s Handbook", "genres": ["Law", "Politics"], "authors": ["Bruce Bueno de Mesquita", "Alastair Smith"], "published": true}');
INSERT INTO books VALUES (4, '{"title": "Deep Work", "genres": ["Productivity", "Reference"], "published": true}');
INSERT INTO books VALUES (5, '{"title": "Siddhartha", "genres": ["Fiction", "Spirituality"], "published": true}');

查询数据

我们现在可以查询JSON数据中的特定键:

SELECT data->'title' AS title FROM books;

这将从JSONB数据中提取的标题作为列返回:

title

---------------------------

"Sleeping Beauties"

"Influence"

"The Dictator's Handbook"

"Deep Work"

"Siddhartha"

(5 rows)

过滤结果

您也可以使用WHERE子句但通过JSON键以正常方式过滤结果集:

SELECT * FROM books WHERE data->'published' = 'false';

在这种情况下,返回原始JSON数据:

book_id | data

---------+-------------------------------------------------------------------------------------------------

1 | {"title": "Sleeping Beauties", "genres": ["Fiction", "Thriller", "Horror"], "published": false}

(1 row)

展开数据

这是一个重要的问题,因为它将使我们能够在处理关系数据库时使用我们熟悉的聚合函数,但是在JSON数据的反直觉环境中也是如此。

SELECT jsonb_array_elements_text(data->'genres') AS genre FROM books WHERE book_id = 1;

这会将JSON数组扩展为一列:

genre

----------

Fiction

Thriller

Horror

(3 rows)

特殊的jsonb功能

除了效率之外,还有其他方法可以让您以二进制形式存储JSON。

其中一个增强功能是GIN(广义倒置索引)索引以及随附的新品牌运营商。

检查遏制(Checking Containment)

Containment测试一个文档(一个集合或一个数组)是否包含在另一个文档中。这可以使用@>运算符在jsonb数据中完成。

例如,数组[“Fiction”,“Horror”]包含在数组[“Fiction”,“Thriller”,“Horror”]中(其中t代表true):

SELECT '["Fiction", "Thriller", "Horror"]'::jsonb @> '["Fiction", "Horror"]'::jsonb;

t

然而,相反的是["Fiction", "Thriller", "Horror"]包含在["Fiction", "Horror"]中,是错误的:

SELECT '["Fiction", "Horror"]'::jsonb @> '["Fiction", "Thriller", "Horror"]'::jsonb;
f

使用这个原则,我们可以轻松检查单一书籍类型:

SELECT data->'title' FROM books WHERE data->'genres' @> '["Fiction"]'::jsonb;
"Sleeping Beauties"
"Siddhartha"

通过传递一个数组(注意它们的关键顺序根本不重要),或者同时使用多个类型:

SELECT data->'title' FROM books WHERE data->'genres' @> '["Fiction", "Horror"]'::jsonb;
"Sleeping Beauties"

此外,从9.5版开始,PostgreSQL引入了检查顶级键和空对象包含的功能:

SELECT '{"book": {"title": "War and Peace"}}'::jsonb @> '{"book": {}}'::jsonb;
t

检查存在

作为包含的变体,jsonb还有一个存在运算符(?),可用于查找是否存在对象键或数组元素。

在这里,让我们计算出输入作者字段的书籍:

SELECT COUNT(*) FROM books WHERE data ? 'authors';

在这种情况下只有一个(“独裁者的手册”):

count

-------

1

(1 row)

创建指数/索引

让我们花点时间提醒自己索引是关系数据库的关键组成部分。没有它们,每当我们需要检索一条信息时,数据库就会扫描整个表格,这当然效率很低。

jsonb相对于json数据类型的显着改进是能够索引JSON数据。

我们的玩具示例只有5个条目,但如果它们是数千或数百万个条目,我们可以通过构建索引来减少一半以上的搜索时间。

例如,我们可以索引出版的书籍:

CREATE INDEX idx_published ON books (data->'published');

由于idx_published索引,这个简单的索引将自动加速我们在已发布的书籍上运行的所有聚合函数(WHERE data - >'published'='true')。

事实上,我们可以 - 并且可能应该在DB大小增加时 - 索引在过滤结果时要在WHERE子句上使用的任何内容。

注意事项

切换到jsonb数据类型时,您需要考虑一些技术细节。

jsonb更严格,因此,除非数据库编码为UTF8,否则它不允许非ASCII字符(U + 007F以上的字符)的Unicode转义。它还拒绝NULL字符(\ u0000),它不能用PostgreSQL的文本类型表示。

它不会保留空白区域,它会剥离JSON字符串中的前导/滞后空白区域以及JSON字符串中的空白区域,所有这些都只会使代码不整齐(毕竟这对你来说可能不是件坏事) 。)

它不保留对象键的顺序,处理键的方式与Python字典中的处理方式非常相似 - 未排序。如果您依赖JSON密钥的顺序,则需要找到解决此问题的方法。

最后,jsonb不会保留重复的对象键(这可能不是一件坏事,特别是如果你想避免数据中的歧义),只存储最后一个条目。

结论

PostgreSQL文档建议大多数应用程序应该更喜欢将JSON数据存储为jsonb,因为我们已经看到有显着的性能增强和仅有的小警告。

jsonb带来的功能非常强大,您可以很好地处理关系数据,就像在常规RDBMS中一样,但是所有这些都在JSON中,并且在性能上有非常显着的提升,结合了NoSQL解决方案的实用性。RDBMS的强大功能。

切换到jsonb时的主要缺点是遗留代码,例如,可能依赖于对象密钥的排序;这是需要更新以按预期工作的代码。并且说明显而易见的是,作为9.4版中引入的一个特性,jsonb不是向后兼容的,你需要使用的jsonb关键字设置JSON表将破坏传统平台上的SQL代码。

最后,请注意我已经涵盖了指数及其运算符的一些典型用法;有关更多详细信息和示例,请查看官方PostgreSQL文档中的jsonb索引以及JSON函数和运算符。

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
弹性计算 关系型数据库 数据库
搭建PostgreSQL主从架构
PostgreSQL是一个关系型数据库管理系统(RDBMS),支持NoSQL数据类型(JSON/XML/hstore)。本教程介绍如何在两台CentOS 7操作系统的ECS实例上搭建PostgreSQL主从架构。
|
3月前
|
NoSQL 关系型数据库 MySQL
微服务架构下的数据库选择:MySQL、PostgreSQL 还是 NoSQL?
在微服务架构中,数据库的选择至关重要。不同类型的数据库适用于不同的需求和场景。在本文章中,我们将深入探讨传统的关系型数据库(如 MySQL 和 PostgreSQL)与现代 NoSQL 数据库的优劣势,并分析在微服务架构下的最佳实践。
|
7月前
|
SQL 关系型数据库 数据库
实时计算 Flink版操作报错之使用SQL 将 PostgreSQL 的 date 类型字段转换为 TIMESTAMP 类型时遇到报错,该如何处理
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
|
6月前
|
消息中间件 Java 关系型数据库
实时计算 Flink版操作报错合集之从 PostgreSQL 读取数据并写入 Kafka 时,遇到 "initial slot snapshot too large" 的错误,该怎么办
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
1022 0
|
3月前
|
XML JSON 关系型数据库
PostgreSQL支持多种数据类型
PostgreSQL支持多种数据类型
170 1
|
4月前
|
运维 监控 关系型数据库
【一文搞懂PGSQL】7. PostgreSQL + repmgr + witness 高可用架构
该文档介绍了如何构建基于PostgreSQL的高可用架构,利用repmgr进行集群管理和故障转移,并引入witness节点增强网络故障检测能力。repmgr是一款轻量级的开源工具,支持一键部署、自动故障转移及分布式节点管理。文档详细描述了环境搭建步骤,包括配置postgresql参数、安装与配置repmgr、注册集群节点以及配置witness节点等。此外,还提供了故障手动与自动切换的方法及常用命令,确保集群稳定运行。
|
4月前
|
SQL 关系型数据库 MySQL
SQL Server、MySQL、PostgreSQL:主流数据库SQL语法异同比较——深入探讨数据类型、分页查询、表创建与数据插入、函数和索引等关键语法差异,为跨数据库开发提供实用指导
【8月更文挑战第31天】SQL Server、MySQL和PostgreSQL是当今最流行的关系型数据库管理系统,均使用SQL作为查询语言,但在语法和功能实现上存在差异。本文将比较它们在数据类型、分页查询、创建和插入数据以及函数和索引等方面的异同,帮助开发者更好地理解和使用这些数据库。尽管它们共用SQL语言,但每个系统都有独特的语法规则,了解这些差异有助于提升开发效率和项目成功率。
489 0
|
5月前
|
SQL 存储 开发者
云架构数据倾斜问题之聚合操作导致数据膨胀如何解决
云架构数据倾斜问题之聚合操作导致数据膨胀如何解决
|
5月前
|
分布式计算 DataWorks 关系型数据库
DataWorks操作报错合集之使用连接串模式新增PostgreSQL数据源时遇到了报错"not support data sync channel, error code: 0001",该怎么办
DataWorks是阿里云提供的一站式大数据开发与治理平台,支持数据集成、数据开发、数据服务、数据质量管理、数据安全管理等全流程数据处理。在使用DataWorks过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
|
5月前
|
SQL 监控 关系型数据库
实时计算 Flink版操作报错合集之在设置监控PostgreSQL数据库时,将wal_level设置为logical,出现一些表更新和删除操作报错,怎么办
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。