데이타베이스/PostgreSQL

PostgreSQL 데이터베이스 설계의 핵심: 배열(Array)과 JSONB 완벽 활용 가이드

shimdh 2025. 10. 30. 23:12
728x90

PostgreSQL은 오픈소스 관계형 데이터베이스 관리 시스템(RDBMS) 중에서도 가장 유연하고 강력한 옵션 중 하나로 평가받습니다. 복잡한 데이터 구조를 효율적으로 저장하고 쿼리할 수 있는 다양한 데이터 타입을 지원하며, 그중에서도 배열(Array)JSONB는 개발자들의 사랑을 독차지하고 있죠. 이 두 타입은 전통적인 테이블 기반 설계의 한계를 넘어, 가변적이고 비정형 데이터까지 손쉽게 다룰 수 있게 해줍니다.

이 글에서는 배열과 JSONB의 기본 개념부터 실제 활용 사례까지 깊이 파헤쳐보겠습니다. 초보자부터 경험 많은 개발자까지, PostgreSQL 프로젝트에서 이 타입들을 어떻게 최적화할 수 있는지 실전 팁을 공유할게요. 만약 당신의 데이터베이스가 더 유연해지길 원한다면, 끝까지 읽어보세요!

728x90

배열(Array) 데이터 타입: 단순성과 효율성의 완벽한 조화

PostgreSQL의 배열 타입은 하나의 열에 여러 값을 저장할 수 있는 강력한 기능입니다. 이는 리스트나 세트 같은 가변 길이 데이터에 딱 맞아요. 기본 타입(정수, 텍스트 등)뿐만 아니라 사용자 정의 타입도 배열 요소로 사용할 수 있어서, 설계 자유도가 무궁무진합니다. 배열은 메모리 효율적이고, 쿼리 성능도 우수해 대규모 데이터셋에서 빛을 발합니다.

배열 열 정의와 데이터 삽입 예시

배열 열을 만드는 건 간단합니다. 테이블 생성 시 타입을 TEXT[]처럼 지정하면 돼요. 아래 예시는 tags라는 텍스트 배열을 가진 example 테이블을 생성하는 코드입니다.

CREATE TABLE example (
    id SERIAL PRIMARY KEY,
    tags TEXT[]
);

데이터 삽입 시 중괄호 {}를 사용해 배열을 표현합니다. 문자열 요소는 쉼표로 구분하세요.

INSERT INTO example (tags) VALUES ('{postgresql, sql, database}');

이렇게 하면 하나의 행에 여러 태그가 저장되며, 필요 시 더 많은 요소를 추가할 수 있습니다.

배열 데이터 쿼리와 조작 팁

PostgreSQL은 배열을 위한 전용 연산자와 함수를 풍부하게 제공합니다. 예를 들어, ANY 연산자로 특정 값이 배열에 포함되어 있는지 확인할 수 있어요. 아래 쿼리는 'sql' 태그가 포함된 행을 검색합니다.

SELECT * FROM example WHERE 'sql' = ANY(tags);

기존 배열에 요소를 추가하거나 제거할 때도 편리합니다. array_append 함수로 새 태그를 덧붙여보죠.

UPDATE example SET tags = array_append(tags, 'new_tag') WHERE id = 1;

추가 팁: 배열 길이를 확인하려면 array_length(tags, 1)을 사용하세요. 중복 제거는 array_agg(DISTINCT ...)와 결합하면 유용합니다. 하지만 배열이 너무 길어지면 인덱싱(GIN 인덱스)을 고려해 성능을 최적화하세요.

실용적인 예: 블로그 카테고리 관리

블로그 플랫폼을 개발할 때, 각 게시물이 여러 카테고리를 가질 수 있어야 하죠? 별도의 카테고리 테이블과 JOIN을 쓰는 대신 배열로 간단히 해결할 수 있습니다. 이는 쿼리를 단순화하고, 읽기 속도를 높여줍니다.

CREATE TABLE blog_posts (
    post_id SERIAL PRIMARY KEY,
    title TEXT NOT NULL,
    categories TEXT[]  -- 카테고리를 배열로 저장
);

INSERT INTO blog_posts (title, categories) VALUES
('Post One', '{Tech, PostgreSQL}'),
('Post Two', '{Lifestyle, Travel}');

이 설계로 "Tech 카테고리의 모든 게시물"을 검색하는 쿼리는 이렇게 간단해집니다:

SELECT title FROM blog_posts WHERE 'Tech' = ANY(categories);

단점으로는 배열 내 중복 관리나 복잡한 관계(예: 카테고리 간 계층)가 생기면 별도 테이블로 전환하는 게 좋습니다. 하지만 가벼운 카테고리 관리라면 배열이 최고의 선택!

JSONB 데이터 타입: 유연한 구조화된 데이터의 절대 강자

JSONB는 JSON 데이터를 바이너리 형식으로 저장하는 타입으로, 검색과 인덱싱 속도가 일반 JSON보다 훨씬 빠릅니다. JSONB는 스키마가 고정되지 않은 데이터(예: API 응답, 사용자 프로필)에 이상적이며, PostgreSQL의 내장 함수로 깊이 있는 조작이 가능합니다. 텍스트 기반 JSON과 달리 압축되어 저장되므로 저장 공간도 절약돼요.

JSONB 열 정의와 데이터 삽입 예시

JSONB 열은 테이블 생성 시 JSONB 타입으로 지정합니다.

CREATE TABLE users (
    user_id SERIAL PRIMARY KEY,
    profile_data JSONB
);

유효한 JSON 객체를 삽입할 때는 문자열로 감싸세요. (SQL에서 따옴표 이스케이프 주의!)

INSERT INTO users (profile_data) VALUES
('{"name": "John Doe", "age": 30, "hobbies": ["reading", "coding"]}'),
('{"name": "Jane Smith", "age": 25, "preferences": {"theme": "dark"}}');

이렇게 하면 중첩 객체와 배열까지 자유롭게 저장됩니다.

JSONB 데이터 쿼리와 조작 팁

JSONB의 매력은 강력한 경로 기반 쿼리입니다. ->> 연산자로 값을 추출하고, 타입 캐스팅으로 필터링할 수 있어요.

SELECT * FROM users WHERE (profile_data->>'age')::int > 28;

특정 키의 값을 업데이트할 때는 jsonb_set 함수를 사용합니다.

UPDATE users SET profile_data = jsonb_set(profile_data, '{age}', '31') WHERE user_id = 1;

팁: GIN 인덱스를 JSONB 열에 적용하면(CREATE INDEX ON users USING GIN (profile_data);) 복잡한 쿼리도 빠르게 처리됩니다. 중첩 키 검색은 @> 연산자(포함 확인)로 간편해요: WHERE profile_data @> '{"hobbies": ["coding"]}'.

실용적인 예: 전자상거래 제품 속성 관리

전자상거래 앱에서 제품마다 다른 속성(크기, 색상, 재질 등)을 다루려면 스키마 변경이 잦아집니다. JSONB로 유연하게 해결하세요!

CREATE TABLE products (
    product_id SERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    details JSONB  -- 제품 속성을 유연한 JSONB로 저장
);

INSERT INTO products (name, details) VALUES
('T-shirt', '{"sizes": ["S", "M", "L"], "colors": ["red", "blue"], "material": "cotton"}'),
('Jeans', '{"sizes": ["M", "L"], "material": "denim", "fit": "slim"}');

"cotton 재질의 모든 제품" 검색:

SELECT name FROM products WHERE details @> '{"material": "cotton"}';

이 접근은 제품 카탈로그가 자주 업데이트될 때 스키마 마이그레이션을 최소화합니다. 다만, JSONB는 관계형 무결성을 약화시킬 수 있으니, 핵심 데이터(예: 가격)는 별도 열로 분리하세요.

결론: 데이터베이스 설계의 새로운 지평을 열다

PostgreSQL의 배열과 JSONB는 전통적인 RDBMS의 경계를 넘어, NoSQL 같은 유연성을 제공합니다. 배열은 단순한 리스트 관리에, JSONB는 복잡한 객체에 최적화되어 있어요. 선택의 핵심은 데이터의 성격: 고정된 구조라면 배열, 진화하는 스키마라면 JSONB를 우선 고려하세요.

이 타입들을 마스터하면 쿼리 성능이 향상되고, 코드 유지보수가 쉬워집니다. 실제 프로젝트에서 테스트해보세요 – 예를 들어, 배열로 태그 클라우드를, JSONB로 사용자 설정을 구현하면 그 차이를 바로 느낄 거예요. PostgreSQL의 잠재력을 최대화하며, 더 스마트한 데이터베이스를 구축해보는 건 어떨까요?

728x90