PostgreSQL에서 많은 개발자들이 정보를 저장할 때 어떤 데이터 구조를 써야 할지 고민하곤 해. 좀 더 단순한 데이터 구조엔 배열(ARRAY)을 쓸까? 아니면 문자열엔 텍스트(TEXT) 컬럼을 쓸까? 혹은 "키-값" 쌍 저장엔 HSTORE가 나을까? 그리고, 언제 JSON이나 JSONB가 진짜 좋은 선택일까 하는 고민도 있지.
이걸 좀 더 쉽게 이해할 수 있게, 각 방식의 장점과 단점, 그리고 실제로 어떻게 쓰는지 예시도 보여줄게.
언제 배열(ARRAY)을 쓰고, 언제 JSONB를 써야 할까?
배열(ARRAY)은 같은 타입의 값들이 쭉 나열된 데이터에 딱 좋아. 예를 들어 학생들의 점수 리스트나, 어떤 레코드에 태그를 붙일 때 배열이 완전 잘 맞아.
배열 예시:
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name TEXT,
grades INTEGER[] -- 점수 배열
);
INSERT INTO students (name, grades)
VALUES ('Alice', ARRAY[90, 85, 88]),
('Bob', ARRAY[70, 75, 78]);
반면에 JSONB는 좀 더 복잡하고, 중첩된 구조에 잘 어울려. 예를 들어 각 점수에 대한 설명 같은 추가 데이터를 저장하고 싶으면 JSONB가 좋아.
JSONB 예시:
CREATE TABLE students_json (
id SERIAL PRIMARY KEY,
name TEXT,
grades JSONB -- 점수에 대한 데이터 객체
);
INSERT INTO students_json (name, grades)
VALUES ('Alice', '{"Math": 90, "Science": 85, "English": 88}'),
('Bob', '{"Math": 70, "Science": 75, "English": 78}');
주요 차이점
| 기준 | 배열(ARRAY) |
JSONB |
|---|---|---|
| 구조 | 같은 타입의 데이터만 | 복잡하고 중첩된 데이터 구조 |
| 데이터 접근 | 인덱스로: grades[1] |
키로: grades->'Math' |
| 인덱스 지원 | 배열 전체에 GIN 또는 BTREE만 |
키별로 GIN과 BTREE 인덱스 편하게 사용 |
| 언제 사용 | 단순 리스트 데이터(태그, 점수, 아이디 등) | 키와 값이 있는 복잡한 객체 |
배열과 JSONB 변환 예시
데이터를 배열에서 JSONB로, 또는 그 반대로 변환하는 방법을 볼게:
배열 → JSONB
SELECT to_jsonb(grades) AS grades_jsonb
FROM students;
-- 결과:
-- [{"90","85","88"}]
JSONB → 배열
SELECT array_agg(value::INTEGER) AS grades_array
FROM jsonb_array_elements_text('["90", "85", "88"]');
-- 결과:
-- {90,85,88}
JSONB와 텍스트 데이터(TEXT) 비교
텍스트 컬럼은 그냥 문자열이나, 구조 없는 작은 데이터를 저장할 때 딱이야. 예를 들어 상품 이름이나 설명처럼 문자열 검색이 필요하면 TEXT가 최고지.
CREATE TABLE books (
id SERIAL PRIMARY KEY,
title TEXT,
description TEXT
);
INSERT INTO books (title, description)
VALUES ('SQL Basics', 'SQL에 대한 간단한 소개'),
('Advanced PostgreSQL', 'PostgreSQL 성능에 대한 심층 가이드');
언제 JSONB를 쓰는 게 더 좋을까?
만약 네 문자열이 중첩 구조를 가진 정보(예: 카테고리와 태그 리스트가 들어간 설명)로 바뀐다면, JSONB가 더 나아.
CREATE TABLE books_json (
id SERIAL PRIMARY KEY,
info JSONB
);
INSERT INTO books_json (info)
VALUES ('{"title": "SQL Basics", "tags": ["beginner", "database"]}'),
('{"title": "Advanced PostgreSQL", "tags": ["performance", "optimization"]}');
주요 차이점
| 기준 | 텍스트(TEXT) |
JSONB |
|---|---|---|
| 구조 | 구조 없는 데이터 | 구조화된, 중첩 데이터 |
| 검색 | 전체 텍스트 검색 | 키, 값, 중첩 구조로 검색 |
| 데이터 변경 | 전체 교체만 가능 | 개별 키만 수정 가능 |
| 언제 사용 | 단순 문자열 | 키-값 구조의 복잡한 데이터 |
JSONB와 HSTORE 비교
HSTORE는 JSONB의 형님 같은 존재로, "키-값" 쌍을 저장할 수 있어. 만약 네 데이터 구조가 단순하고(중첩이나 배열 필요 없음), HSTORE가 더 가볍고 빠를 수 있어.
CREATE TABLE products (
id SERIAL PRIMARY KEY,
attributes HSTORE
);
INSERT INTO products (attributes)
VALUES ('"color"=>"red", "size"=>"M"'),
('"color"=>"blue", "size"=>"L"');
왜 JSONB가 HSTORE를 대체했을까?
HSTORE는 "키-값" 쌍에 편리하지만, 중첩이나 배열을 지원하지 않아서 JSONB가 더 범용적으로 쓰이게 됐어. 단순한 객체에서 더 복잡한 구조로 넘어가면 JSONB가 자연스러운 선택이야.
주요 차이점
| 기준 | HSTORE | JSONB |
|---|---|---|
| 구조 | 중첩 없는 "키-값" 쌍 | 완전한 중첩 구조 |
| 배열 지원 | 아니 | 응 |
| 검색 | 키로만 검색 | 키, 값, 중첩 구조로 검색 |
| 언제 사용 | 단순 키-값 | 복잡한 데이터 구조 |
적절한 데이터 타입 고르는 법?
만약 네가:
- 단순 구조 — 리스트나 같은 타입 데이터면 배열(
ARRAY)을 써. - 단순 문자열이나 설명이면 텍스트 컬럼(
TEXT)을 써. - 중첩 없는 "키-값" 쌍이면
HSTORE를 골라. - 중첩 객체, 배열, 복잡한 데이터 구조면 JSONB가 필요해.
포맷 간 변환 예시
TEXT → JSONB
SELECT to_jsonb('간단한 텍스트 예시') AS jsonb_form;
-- 결과: "간단한 텍스트 예시"
JSONB → TEXT
SELECT info::TEXT AS text_form
FROM books_json;
-- 결과: {"title": "SQL Basics", "tags": ["beginner", "database"]}
HSTORE → JSONB
SELECT hstore_to_jsonb(attributes) AS jsonb_form
FROM products;
-- 결과: {"color": "red", "size": "M"}
JSONB → HSTORE
SELECT jsonb_to_hstore('{"color": "red", "size": "M"}') AS hstore_form;
-- 결과: "color"=>"red", "size"=>"M"
뭐에 신경 써야 할까?
최대의 유연성과 복잡한 구조 지원이 필요하면 JSONB를 골라. 하지만 네 작업이 배열, 텍스트, "키-값" 쌍처럼 단순한 데이터 구조라면 각각에 맞는 데이터 타입(ARRAY, TEXT, HSTORE)을 쓰는 게 좋아.
데이터 구조를 잘 고르면 나중에 개발할 때 골치 아픈 일도 줄고, 쿼리 성능도 더 좋아질 거야.
GO TO FULL VERSION