【PostgreSQL】利用PostgreSQL中的NoSQL功能

视频号

微信公众号

知识星球

Chinese, Simplified

NoSQL文档存储非常适合管理大量非结构化数据。但是,有些组织使用非结构化数据,但仍然需要传统SQL数据库所具备的功能。例如,媒体或新闻内容机构可能会运行以大量文本和图像内容为中心的高流量网站。尽管他们需要存储这些非结构化数据,但他们可能并不真正需要NoSQL数据库所附带的灵活模式或水平可扩展性。相反,他们需要PostgreSQL这样的关系数据库所带来的数据库管理的易用性和一致性。

有可能两全其美吗?对

PostgreSQL的数据类型旨在支持非结构化数据,它提供了一个愉快的媒介,使您能够在一个经济高效且易于管理的关系数据库中利用NoSQL功能。在本文中,我们将研究如何使用PostgreSQL中的HStore和JSONB数据类型来处理非结构化数据。

在我们深入讨论之前,让我们简要了解一下SQL和NoSQL数据库之间的主要区别。

理解SQL与NoSQL

SQL和NoSQL数据库各有其独特的优势和劣势。对于哪种最能满足您的数据需求,做出明智的决定取决于对其差异的深刻理解。

SQL(关系型)数据库,如PostgreSQL和MySQL,在表、行和列中以清晰和可预测的结构表示数据。它们遵循ACID属性(原子性、一致性、隔离性和持久性),通过确保数据库事务得到可靠处理,为数据完整性奠定了坚实的基础。

SQL数据库在数据一致性和完整性至关重要的地方大放异彩,例如在处理复杂查询和事务系统(如金融应用程序)时。

相比之下,NoSQL数据库(文档存储)满足了不一定适用于表格表示的大量变化的数据集。NoSQL数据库的例子包括MongoDB、Cassandra和Couchbase。NoSQL数据库使用灵活的模式,允许数据结构随着时间的推移而发展。它们还支持水平可扩展性,将数据分布在多个服务器上,以改进对大数据负载和高流量的处理。

NoSQL数据库通常用于可扩展性至关重要的应用程序,例如在实时应用程序或大型语言模型(LLM)中处理大量数据。NoSQL数据库在处理不断变化的数据结构时也很有用,因为它们允许组织根据数据需求的变化进行调整。

为什么您可以使用PostgreSQL作为文档存储?

PostgreSQL是一个关系型数据库,因此将其视为满足NoSQL需求的选项似乎是不传统的。然而,您的情况可能有充分的理由使用PostgreSQL作为文档存储。

如果您的数据存储需求多种多样——既需要结构化的、符合ACID的数据存储,也需要灵活的、无模式的文档存储——那么您可以利用PostgreSQL来组合关系模型和非关系模型。或者,也许您想要某些NoSQL功能,但也想要ACID属性提供的数据一致性保证。最后,作为一种拥有活跃社区的成熟技术,PostgreSQL提供了全面的SQL支持、高级索引和全文搜索。这些特性,再加上它的NoSQL功能,使PostgreSQL成为一个通用的数据存储解决方案。

将PostgreSQL用于NoSQL样式数据的局限性

尽管PostgreSQL具有多功能性,但与传统的NoSQL数据库相比,它有一定的局限性。虽然PostgreSQL可以垂直扩展,但它本身并不支持水平扩展或具有自动分片的分布式数据,这是NoSQL数据库通常提供的功能。PostgreSQL也不为某些NoSQL数据结构(如宽列存储或图形数据库)提供优化。最后,PostgreSQL没有为优化性能提供可调的一致性,这可能来自一些NoSQL数据库。

当您考虑将PostgreSQL用于大型非结构化数据集时,要知道这些限制可能会影响性能和扩展能力。此外,混合使用SQL和NoSQL数据操作会带来复杂性。仔细规划和理解这两种模式将帮助您避免潜在的陷阱。

然而,有了正确的理解和用例,PostgreSQL可以作为一个强大的工具,提供SQL和NoSQL世界中最好的。

PostgreSQL中的HStore和JSONB

当我们考虑使用PostgreSQL作为NoSQL解决方案的可能性时,我们遇到了三种提供类似NoSQL功能的数据类型,但它们都有独特的特征和用例。

  • HStore:这种数据类型允许您将键值对存储在单个PostgreSQL值中。它对于存储没有固定模式的半结构化数据非常有用。
  • JSONB:这是类JSON数据的二进制表示。与HStore相比,它可以存储更复杂的结构,并支持完整的JSON功能。JSONB是可索引的,是处理大量数据的好选择。
  • JSON:这类似于JSONB,尽管它缺乏JSONB的许多功能和效率。JSON数据类型存储输入文本的精确副本,其中包括空白和重复键。

当您不需要JSONB提供的全部功能时,我们提到JSON数据类型是存储JSON格式数据的有效选择。然而,本文剩余部分的主要关注点将是HStore和JSONB。

HStore

PostgreSQL文档将HStore描述为“具有许多很少检查的属性或半结构化数据的行”时非常有用。在使用HStore数据类型之前,请确保启用HStore扩展:

> CREATE EXTENSION hstore;

HStore表示为零个或多个键=>值,用逗号分隔。对的顺序不重要,也不可靠地保留在输出中。

> SELECT 'foo => bar, prompt => "hello world", pi => 3.14'::hstore;
                      hstore                       
-----------------------------------------------------
"pi"=>"3.14", "foo"=>"bar", "prompt"=>"hello world"
(1 row)

每个HStore密钥都是唯一的。如果HStore声明使用重复的密钥,则只会存储其中一个重复密钥,并且不能保证是哪一个。

> SELECT 'key => value1, key => value2'::hstore;
    hstore     
-----------------
"key"=>"value1"
(1 row)

凭借其扁平的键值结构,HStore提供了简单快捷的查询,非常适合简单的场景。然而,HStore只支持文本数据,不支持嵌套数据,这使得它仅限于复杂的数据结构。

另一方面,JSONB可以处理更广泛的数据类型。

JSONB

JSONB数据类型接受JSON格式的输入文本,然后将其存储为分解的二进制格式。尽管这种转换会使输入稍微慢一点,但结果是处理速度快,索引效率高。JSONB不保留空白或对象键的顺序。

> SELECT '{"foo": "bar", "pi": 3.14, "nested": { "prompt": "hello", "count": 5 } }'::jsonb;
                                jsonb                                
-----------------------------------------------------------------------
{"pi": 3.14, "foo": "bar", "nested": {"count": 5, "prompt": "hello"}}
(1 row)

如果给定了重复的对象键,则保留最后一个值。

> SELECT '{"key": "value1", "key": "value2"}'::jsonb;
      jsonb      
-------------------
{"key": "value2"}
(1 row)

由于JSONB支持复杂的结构和完整的JSON功能,因此它是复杂或嵌套数据的理想选择,优于HStore或JSON。但是,与HStore相比,使用JSONB会带来一些性能开销和增加的存储使用量。

实际示例:使用HStore和JSONB

让我们考虑一些实际的例子来演示如何使用这些数据类型。我们将学习创建表、基本查询和操作以及索引。

基本HStore操作

与使用任何其他数据类型一样,您可以将PostgreSQL数据表中的字段定义为HStore数据类型。

> CREATE TABLE articles ( id serial primary key, title varchar(64), meta hstore );

插入具有HStore属性的记录如下所示:

> INSERT INTO articles (title, meta)
  VALUES (
    'Data Types in PostgreSQL',
    'format => blog, length => 1350, language => English, license => "Creative Commons"');

> SELECT * FROM articles;
id |          title           | meta                                     ----+--------------------------+------------------------------------------  1 | Data Types in PostgreSQL | "format"=>"blog", "length"=>"1350", "license"=>"Creative Commons", "language"=>"English"(1 row)

使用HStore字段,您可以从字段中提取由您提供的键指定的特定键值对:

> SELECT title,          meta -> 'license' AS license,         meta -> 'format' AS format  FROM articles;
              title              |     license      |   format  
---------------------------------+------------------+------------
Data Types in PostgreSQL        | Creative Commons | blog
Advanced Querying in PostgreSQL | None             | blog
Scaling PostgreSQL              | MIT              | blog
PostgreSQL Fundamentals         | Creative Commons | whitepaper
(4 rows)

您还可以使用基于HStore字段中特定值的条件进行查询。

> SELECT id, title FROM articles WHERE meta -> 'license' = 'Creative Commons';

id |          title          
----+--------------------------
  1 | Data Types in PostgreSQL
  4 | PostgreSQL Fundamentals
(2 rows)

您有时可能只想查询HStore字段中包含特定键的行。例如,以下查询只返回元HStore中包含注释键的行。要做到这一点,你会使用?操作人员

> SELECT title, meta->'note' AS note FROM articles WHERE meta ? 'note';
              title              |      note      
---------------------------------+-----------------
PostgreSQL Fundamentals         | hold for review
Advanced Querying in PostgreSQL | needs edit
(2 rows)

这里列出了一些有用的HStore运算符和函数。例如,您可以将HStore的密钥提取到数组中,也可以将HSstore转换为JSON表示。

> SELECT title, akeys(meta) FROM articles where id=1;
          title           |              akeys              
--------------------------+----------------------------------
Data Types in PostgreSQL | {format,length,license,language}
(1 row)

> SELECT title, hstore_to_json(meta) FROM articles where id=1;
          title           |            hstore_to_json
--------------------------+------------------------------------------------
Data Types in PostgreSQL | {"format": "blog", "length": "1350", "license": "Creative Commons", "language": "English"}
(1 row)

基本JSONB操作

在PostgreSQL中使用JSONB数据类型非常简单。表创建和记录插入如下所示:

> CREATE TABLE authors (id serial primary key, name varchar(64), meta jsonb);

> INSERT INTO authors (name, meta)  VALUES    ('Adam Anderson',     '{ "active":true, "expertise": ["databases", "data science"], "country": "UK" }');

请注意,jsonb元字段是以JSON格式的文本字符串提供的。如果您提供的值不是有效的JSON,PostgreSQL会抱怨。

> INSERT INTO authors (name, meta)  VALUES ('Barbara Brandini', '{ "this is not valid JSON" }');
ERROR:  invalid input syntax for type json

错误:json类型的输入语法无效

与HStore类型不同,JSONB支持嵌套数据。

> INSERT INTO authors (name, meta)  VALUES ('Barbara Brandini',          '{ "active":true,             "expertise": ["AI/ML"],             "country": "CAN",             "contact": {               "email": "barbara@example.com",               "phone": "111-222-3333"             }           }');

与HStore类似,JSONB字段可以部分检索,只使用某些键。例如:

> SELECT name, meta -> 'country' AS country FROM authors; name | country ------------------+--------- Adam Anderson | "UK" Barbara Brandini | "CAN" Charles Cooper | "UK"(3 rows)

JSONB数据类型有许多在用法上与HStore相似的运算符。例如,以下使用?运算符只检索元字段中包含联系人关键字的那些行。

> SELECT name, meta -> 'active' AS active, meta -> 'contact' AS contact FROM authors WHERE meta ? 'contact'; name | active | contact ------------------+--------+----------------------------------------------- Barbara Brandini | true | {"email": "barbara@example.com", "phone": "111-222-3333"} Charles Cooper | false | {"email": "charles@example.com"} (2 rows)

使用索引

根据文档,HStore数据类型“支持@>、?、?&和?|运算符的GiST和GIN索引。”有关这两种类型索引之间差异的详细解释,请参阅此处。JSONB的索引使用GIN索引来促进对键或键值对的有效搜索。

创建索引的语句如下所示:

> CREATE INDEX idx_hstore ON articles USING GIN(meta);
> CREATE INDEX idx_jsonb ON authors USING GIN(meta);

具有NoSQL灵活性的SQL结构

让我们回顾一下我们在引言中提到的原始用例。想象一下,一家新闻内容机构以与NoSQL文档存储非常相似的方式存储文章。也许文章可以在JSON中表示为表示部分的有序对象数组,每个部分都有文本内容、符号和格式。此外,每一篇文章都关联着大量的元数据,这些元数据属性在一篇文章与下一篇文章之间是不一致的。

上面的描述概括了组织的大部分NoSQL需求,但它如何管理和组织数据的其他一切都与关系数据模型密切相关。

通过将JSONB等数据类型的NoSQL功能与PostgreSQL的传统SQL优势相结合,组织可以在嵌套数据中享受灵活的模式和快速查询,同时仍然能够执行联合操作和强制执行数据关系。PostgreSQL的HStore和JSONB数据类型为那些需要关系数据库结构但也需要NoSQL风格数据存储的开发人员提供了强大的选择。

PostgreSQL规模

您是否希望在传统关系数据库的框架内支持NoSQL风格的数据存储和查询?也许您的组织处理文档的方式与我们在本文中描述的类似。或者,您正在为大型语言模型(LLM)或其他一些AI/ML项目寻找处理非结构化数据存储的选项。

Linode Marketplace中的PostgreSQL集群为您提供了SQL数据库的关系模型和结构,以及NoSQL数据库的水平可扩展性。将其与使用HStore或JSONB数据类型相结合,您就有了一个理想的混合解决方案,可以在PostgreSQL中使用NoSQL功能。

本文地址
https://architect.pub/harnessing-nosql-capabilities-postgresql
SEO Title
Harnessing NoSQL Capabilities in PostgreSQL