So sánh JSON với các kiểu khác: ARRAY, TEXT, HSTORE
Trong PostgreSQL, nhiều dev thường gặp câu hỏi: nên dùng cấu trúc dữ liệu nào để lưu thông tin? Dùng mảng (ARRAY) cho cấu trúc dữ liệu đơn giản? Hay trường text (TEXT) cho chuỗi? Hoặc HSTORE để lưu các cặp "khóa-giá trị"? Và tất nhiên, câu hỏi lớn: khi nào thì nên dùng JSON hoặc JSONB?
Để giúp bạn rõ hơn, tụi mình sẽ nói về ưu nhược điểm của từng cách, kèm ví dụ sử dụng thực tế.
Khi nào dùng mảng (ARRAY), khi nào dùng JSONB?
Mảng (ARRAY) cực hợp cho dữ liệu đồng nhất, kiểu như một danh sách các giá trị cùng loại. Ví dụ, nếu bạn có danh sách điểm số của sinh viên hoặc các tag cho một bản ghi, mảng là best choice.
Ví dụ về mảng:
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name TEXT,
grades INTEGER[] -- mảng điểm số
);
INSERT INTO students (name, grades)
VALUES ('Alice', ARRAY[90, 85, 88]),
('Bob', ARRAY[70, 75, 78]);
Mặt khác, JSONB hợp với cấu trúc phức tạp, lồng nhau. Nếu bạn muốn lưu thêm info cho từng điểm, ví dụ mô tả từng điểm số, thì JSONB là chuẩn bài.
Ví dụ về JSONB:
CREATE TABLE students_json (
id SERIAL PRIMARY KEY,
name TEXT,
grades JSONB -- object chứa info điểm số
);
INSERT INTO students_json (name, grades)
VALUES ('Alice', '{"Toán": 90, "Khoa học": 85, "Tiếng Anh": 88}'),
('Bob', '{"Toán": 70, "Khoa học": 75, "Tiếng Anh": 78}');
Khác biệt chính
| Tiêu chí | Mảng (ARRAY) |
JSONB |
|---|---|---|
| Cấu trúc | Dữ liệu đồng nhất cùng kiểu | Cấu trúc dữ liệu phức tạp, lồng nhau |
| Truy cập dữ liệu | Theo index: grades[1] |
Theo key: grades->'Toán' |
| Hỗ trợ index | Chỉ GIN hoặc BTREE cho cả mảng |
Index GIN và BTREE tiện cho từng key |
| Khi nào dùng | Danh sách đơn giản (tag, điểm số, id) | Object phức tạp với key và value |
Ví dụ chuyển đổi giữa mảng và JSONB
Cùng xem cách chuyển dữ liệu giữa mảng và JSONB nhé:
Mảng → JSONB
SELECT to_jsonb(grades) AS grades_jsonb
FROM students;
-- Kết quả:
-- [{"90","85","88"}]
JSONB → Mảng
SELECT array_agg(value::INTEGER) AS grades_array
FROM jsonb_array_elements_text('["90", "85", "88"]');
-- Kết quả:
-- {90,85,88}
So sánh JSONB và dữ liệu text (TEXT)
Trường text cực hợp nếu bạn chỉ cần lưu chuỗi hoặc dữ liệu không có cấu trúc. Nếu bạn chỉ cần tìm kiếm theo chuỗi, ví dụ tên sản phẩm hoặc mô tả, TEXT là lựa chọn hợp lý.
CREATE TABLE books (
id SERIAL PRIMARY KEY,
title TEXT,
description TEXT
);
INSERT INTO books (title, description)
VALUES ('Cơ bản SQL', 'Giới thiệu ngắn gọn về SQL'),
('PostgreSQL nâng cao', 'Hướng dẫn chi tiết về hiệu năng PostgreSQL');
Khi nào nên dùng JSONB?
Nếu chuỗi của bạn bắt đầu thành info có cấu trúc lồng nhau (ví dụ mô tả có category và danh sách tag), nên chọn JSONB.
CREATE TABLE books_json (
id SERIAL PRIMARY KEY,
info JSONB
);
INSERT INTO books_json (info)
VALUES ('{"title": "Cơ bản SQL", "tags": ["người mới", "cơ sở dữ liệu"]}'),
('{"title": "PostgreSQL nâng cao", "tags": ["hiệu năng", "tối ưu"]}');
Khác biệt chính
| Tiêu chí | Text (TEXT) |
JSONB |
|---|---|---|
| Cấu trúc | Dữ liệu không có cấu trúc | Dữ liệu có cấu trúc, lồng nhau |
| Tìm kiếm | Tìm kiếm toàn văn bản | Tìm theo key, value, cấu trúc lồng nhau |
| Thay đổi dữ liệu | Chỉ thay thế toàn bộ | Thay đổi từng key riêng lẻ |
| Khi nào dùng | Chuỗi text đơn giản | Dữ liệu phức tạp kiểu key-value |
So sánh JSONB và HSTORE
HSTORE là kiểu dữ liệu "anh cả" của JSONB, cho phép lưu các cặp "khóa-giá trị". Nếu cấu trúc dữ liệu của bạn đơn giản (không cần lồng nhau hay mảng), HSTORE sẽ nhẹ và nhanh hơn.
CREATE TABLE products (
id SERIAL PRIMARY KEY,
attributes HSTORE
);
INSERT INTO products (attributes)
VALUES ('"màu"=>"đỏ", "size"=>"M"'),
('"màu"=>"xanh", "size"=>"L"');
Tại sao JSONB thay thế HSTORE?
Dù HSTORE tiện cho cặp "khóa-giá trị", nó không hỗ trợ lồng nhau hay mảng, nên JSONB đa năng hơn nhiều. Khi bạn cần object phức tạp hơn, JSONB là bước tiếp theo tự nhiên.
Khác biệt chính
| Tiêu chí | HSTORE | JSONB |
|---|---|---|
| Cấu trúc | Cặp "khóa-giá trị", không lồng nhau | Cấu trúc lồng nhau đầy đủ |
| Hỗ trợ mảng | Không | Có |
| Tìm kiếm | Chỉ theo key | Theo key, value, cấu trúc lồng nhau |
| Khi nào dùng | Key-value đơn giản | Cấu trúc dữ liệu phức tạp |
Làm sao chọn kiểu dữ liệu phù hợp?
Nếu bạn có:
- Cấu trúc đơn giản — danh sách hoặc dữ liệu đồng nhất, dùng mảng (
ARRAY). - Chuỗi đơn giản hoặc mô tả, dùng trường text (
TEXT). - Cặp "khóa-giá trị" không lồng nhau, chọn
HSTORE. - Object lồng nhau, mảng, cấu trúc phức tạp — bạn cần JSONB.
Ví dụ chuyển đổi giữa các định dạng
TEXT → JSONB
SELECT to_jsonb('Ví dụ text đơn giản') AS jsonb_form;
-- Kết quả: "Ví dụ text đơn giản"
JSONB → TEXT
SELECT info::TEXT AS text_form
FROM books_json;
-- Kết quả: {"title": "Cơ bản SQL", "tags": ["người mới", "cơ sở dữ liệu"]}
HSTORE → JSONB
SELECT hstore_to_jsonb(attributes) AS jsonb_form
FROM products;
-- Kết quả: {"màu": "đỏ", "size": "M"}
JSONB → HSTORE
SELECT jsonb_to_hstore('{"màu": "đỏ", "size": "M"}') AS hstore_form;
-- Kết quả: "màu"=>"đỏ", "size"=>"M"
Lưu ý gì khi chọn?
Nếu bạn cần linh hoạt tối đa và hỗ trợ cấu trúc phức tạp, chọn JSONB. Nhưng nếu bài toán chỉ cần cấu trúc đơn giản như mảng, text hoặc cặp "khóa-giá trị", hãy dùng kiểu dữ liệu tương ứng (ARRAY, TEXT, HSTORE).
Đừng quên, chọn đúng cấu trúc dữ liệu sẽ giúp bạn tránh đau đầu về sau và tăng hiệu năng cho query của bạn.
GO TO FULL VERSION