MySQL의 JSON 지원은 MySQL 5.7.8 버전부터 시작되었다. 이는 2015년 10월 21일에 정식 출시된 MySQL 5.7의 주요 기능 중 하나이다.
-- MySQL 5.7.8 (2015년) - JSON 데이터 타입 최초 도입
-- MySQL 8.0 (2018년) - JSON 기능 대폭 향상, JSON_TABLE() 함수 추가
-- MySQL 8.0.19 이후 - 성능 최적화 및 추가 기능
MySQL JSON 지원의 핵심 특징:
-- 테이블 생성 시 JSON 컬럼 정의
CREATE TABLE products (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100),
details JSON
);
MySQL은 JSON 데이터를 텍스트로 저장하지 않고 최적화된 바이너리 형식으로 변환하여 저장한다.
핵심 저장 특징:
MySQL에서 JSON을 어떻게 저장하는지 자세하게 알고 싶다면 아래 글을 참고하면 좋을 것 같다.
참고: - MySQL Json 데이터 타입의 저장 구조와 성능 비교
-- JSON 데이터 삽입
INSERT INTO products (name, details) VALUES
('Laptop', '{"price": 1200, "brand": "Dell", "specs": {"ram": "16GB", "storage": "512GB SSD"}}'),
('Phone', '{"price": 800, "brand": "Samsung", "features": ["5G", "Wireless Charging"]}');
-- JSON 함수를 사용한 삽입
INSERT INTO products (name, details) VALUES
('Tablet', JSON_OBJECT('price', 600, 'brand', 'Apple', 'color', 'Space Gray'));
-- JSON 문서의 저장 공간 확인
SELECT
name,
JSON_STORAGE_SIZE(details) AS storage_bytes,
JSON_STORAGE_FREE(details) AS free_bytes
FROM products;
-- 기본 문법
SELECT JSON_EXTRACT(details, '$.price') AS price FROM products;
-- 단축 문법 (-> 연산자)
SELECT details->'$.price' AS price FROM products;
-- 따옴표 제거 (->> 연산자)
SELECT details->>'$.brand' AS brand FROM products;
저장되어있는 JSON 구조
{
"price": 1200,
"brand": "Dell",
"specs": {
"ram": "16GB",
"storage": "512GB SSD"
}
}
-- 중첩된 JSON 객체 조회
SELECT
name,
details->'$.specs.ram' AS ram,
details->'$.specs.storage' AS storage
FROM products
WHERE name = 'Laptop';
-- 배열의 첫 번째 요소
SELECT details->'$.features[0]' AS first_feature FROM products;
-- 배열의 모든 요소
SELECT JSON_EXTRACT(details, '$.features[*]') AS all_features FROM products;
-- 특정 값으로 필터링
SELECT * FROM products
WHERE details->'$.price' > 700;
-- JSON 키 존재 확인
SELECT * FROM products
WHERE JSON_CONTAINS_PATH(details, 'one', '$.warranty');
-- 배열에서 특정 값 검색
SELECT * FROM products
WHERE JSON_SEARCH(details, 'one', '5G') IS NOT NULL;
MySQL 8.0 버전 이전에는 다음과 같이 수정
-- 새로운 키-값 추가
UPDATE products
SET details = JSON_SET(details, '$.warranty', '2 years')
WHERE name = 'Laptop';
-- 기존 값 변경
UPDATE products
SET details = JSON_REPLACE(details, '$.price', 1100)
WHERE name = 'Laptop';
-- 키 제거
UPDATE products
SET details = JSON_REMOVE(details, '$.color')
WHERE name = 'Tablet';
참고로 MySQL 8.0부터는 JSON 부분 업데이트(Partial Update) 최적화가 도입되었다. 이는 큰 JSON 문서에서 작은 부분만 수정할 때 성능을 대폭 향상 시키는 이점이 있다.
기존 방식 (MySQL 5.7):
새로운 방식 (MySQL 8.0+):
-- 부분 업데이트 조건을 만족하는 예시
-- ✅ 동일한 컬럼에서 읽고 쓰기
UPDATE products
SET details = JSON_SET(details, '$.last_updated', NOW())
WHERE id = 1;
-- ✅ 여러 JSON 함수 조합 가능
UPDATE products
SET details = JSON_SET(
JSON_REPLACE(details, '$.price', 999),
'$.updated_at', NOW()
)
WHERE id = 1;
-- ❌ 부분 업데이트 불가능한 경우 (다른 컬럼)
UPDATE products
SET details = JSON_SET(other_column, '$.price', 999) -- 다른 컬럼 참조
WHERE id = 1;
JSON 컬럼에 직접 인덱스를 생성할 수는 없지만, 가상 컬럼을 활용하여 인덱싱할 수 있다.
-- 가상 컬럼 생성 및 인덱싱
ALTER TABLE products
ADD COLUMN price_virtual DECIMAL(10,2)
GENERATED ALWAYS AS (details->'$.price') STORED;
CREATE INDEX idx_price ON products(price_virtual);
-- 인덱스를 활용한 빠른 검색
SELECT * FROM products WHERE price_virtual > 700;
위에서 잠깐 언급했던 부분 업데이트도 눈에 띄는 변화라고 생각하는데 가장 눈에 들어왔던것은 JSON_TABLE() 이다. 이는 JSON을 관계형 테이블로 변환시켜주는 함수이다.
-- JSON_TABLE(): JSON을 관계형 테이블로 변환
SELECT j.*
FROM products,
JSON_TABLE(details, '$.features[*]'
COLUMNS (
feature VARCHAR(50) PATH '$'
)
) AS j
WHERE name = 'Phone';
MySQL JSON에 대한 여러 정보를 찾아보던 중 기존 JSON을 저장하던 대표적인 MongoDB를 그럼 이제 쓰지 않아도 되는건지 어떤 차이가 있는건지 궁금해서 찾아봣다.
MySQL JSON의 강점:
MongoDB의 강점:
✅ 이런 경우에 MySQL JSON을 선택하면 좋을 것 같다.
✅ 이런 경우에 MongoDB를 선택하면 좋을 것 같다.