NoSQL 문서 저장소는 대량의 비정형 데이터를 관리하는 데 이상적입니다. 그러나 일부 조직은 비정형 데이터로 작업하지만 여전히 기존 SQL 데이터베이스의 기능을 원합니다. 예를 들어, 미디어 또는 뉴스 콘텐츠 에이전시에서는 방대한 양의 텍스트와 이미지 콘텐츠를 중심으로 트래픽이 많은 웹사이트를 운영할 수 있습니다. 이러한 비정형 데이터를 저장해야 하지만, NoSQL 데이터베이스의 유연한 스키마나 수평적 확장성은 필요하지 않을 수도 있습니다. 대신, PostgreSQL과 같은 관계형 데이터베이스가 제공하는 데이터베이스 관리의 용이성과 일관성이 필요합니다.
두 가지 장점을 모두 누릴 수 있나요? 네. 가능합니다.
비정형 데이터를 지원하도록 설계된 데이터 유형을 갖춘 PostgreSQL은 비용 효율적이고 관리가 간편한 관계형 데이터베이스 내에서 NoSQL 기능을 활용할 수 있는 행복한 매체를 제공합니다. 이 글에서는 PostgreSQL에서 HStore 및 JSONB 데이터 유형을 사용하여 비정형 데이터로 작업하는 방법을 살펴봅니다.
자세히 알아보기 전에 SQL 데이터베이스와 NoSQL 데이터베이스의 주요 차이점을 간략히 살펴보겠습니다.
SQL과 NoSQL 이해
SQL 데이터베이스와 NoSQL 데이터베이스는 각각 고유한 장단점이 있습니다. 데이터 요구 사항을 가장 잘 충족할 수 있는 데이터베이스를 결정하려면 두 데이터베이스의 차이점을 잘 이해해야 합니다.
PostgreSQL 및 MySQL과 같은 SQL(관계형) 데이터베이스는 테이블, 행, 열의 명확하고 예측 가능한 구조로 데이터를 표현합니다. 이러한 데이터베이스는 ACID 속성 (원자성, 일관성, 격리성, 내구성)을 준수하여 데이터베이스 트랜잭션이 안정적으로 처리되도록 보장함으로써 데이터 무결성을 위한 강력한 기반을 제공합니다.
SQL 데이터베이스는 금융 애플리케이션과 같이 복잡한 쿼리 및 트랜잭션 시스템을 처리할 때와 같이 데이터 일관성과 무결성이 중요한 경우에 그 진가를 발휘합니다.
이와는 대조적으로, NoSQL 데이터베이스(문서 저장소)는 표 형식의 표현에 적합하지 않은 크고 다양한 데이터 집합을 처리합니다. NoSQL 데이터베이스의 예로는 MongoDB, Cassandra, Couchbase 등이 있습니다. NoSQL 데이터베이스는 유연한 스키마로 작동하므로 시간이 지남에 따라 데이터 구조가 진화할 수 있습니다. 또한 수평적 확장성을 지원하여 여러 서버에 데이터를 분산함으로써 대용량 데이터 로드와 트래픽을 보다 효율적으로 처리할 수 있습니다.
NoSQL 데이터베이스는 실시간 애플리케이션이나 대규모 언어 모델(LLM)에서 대량의 데이터를 처리하는 등 확장성이 중요한 애플리케이션에서 자주 사용됩니다. 또한 NoSQL 데이터베이스는 조직이 데이터 요구 사항의 변화에 따라 적응할 수 있으므로 다양하고 진화하는 데이터 구조를 처리할 때 유용합니다.
문서 저장소로 PostgreSQL을 사용해야 하는 이유는 무엇인가요?
PostgreSQL은 관계형 데이터베이스이므로 NoSQL 요구 사항을 충족하기 위한 옵션으로 간주하는 것이 이상하게 보일 수 있습니다. 하지만 상황에 따라 PostgreSQL을 문서 저장소로 사용해야 하는 강력한 사례가 있을 수 있습니다.
데이터 스토리지 요구사항이 다양한 경우, 즉 구조화된 ACID 호환 데이터 스토리지와 스키마가 필요 없는 유연한 문서 스토리지가 모두 필요한 경우 PostgreSQL을 활용하여 관계형 모델과 비관계형 모델을 결합할 수 있습니다. 또는 특정 NoSQL 기능을 원하지만 ACID 속성과 함께 제공되는 데이터 일관성 보장을 원할 수도 있습니다. 마지막으로, 활발한 커뮤니티를 갖춘 성숙한 기술인 PostgreSQL은 포괄적인 SQL 지원, 고급 인덱싱 및 전체 텍스트 검색을 제공합니다. 이러한 기능들은 NoSQL 기능과 결합되어 PostgreSQL을 다용도 데이터 스토리지 솔루션으로 만들어 줍니다.
NoSQL 스타일 데이터에 PostgreSQL을 사용할 때의 제한 사항
다양한 기능에도 불구하고 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는 쉼표로 구분된 0개 이상의 키 => 값으로 표시됩니다. 쌍의 순서는 출력 시 중요하지 않거나 안정적으로 유지되지 않습니다.
> 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보다 선호됩니다. 그러나 JSONB를 사용하면 HStore에 비해 약간의 성능 오버헤드와 스토리지 사용량이 증가합니다.
실용적인 예제: 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의 키를 배열로 추출하거나 HStore를 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
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 작업을 위해 비정형 데이터의 저장을 처리할 수 있는 옵션을 찾고 계실 수도 있습니다.
리노드 Marketplace 의 PostgreSQL 클러스터는 SQL 데이터베이스의 관계형 모델 및 구조와 NoSQL 데이터베이스의 수평적 확장성을 함께 제공합니다. 이를 HStore 또는 JSONB 데이터 유형 사용과 결합하면 PostgreSQL 내에서 작업할 때 NoSQL 기능을 활용할 수 있는 이상적인 하이브리드 솔루션을 갖추게 됩니다.
내용