数组和JSONB的对比
今天我们要更深入地理解数组,也要把它和JSONB做个全面对比,看看各自的优缺点,以及在实际项目里怎么用才最爽。
数组 vs JSONB:数据小乌龟 vs 灵活百宝箱
你应该已经知道,PostgreSQL里的数组只能存一种类型的数据:比如数字、字符串或者日期。举个例子:学生的成绩单,每个元素都是数字。
-- 学生和他们成绩的表
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name TEXT,
grades INTEGER[] -- 成绩数组
);
JSONB和数组不一样,它是以JSON结构存数据的。很像大家熟悉的JavaScript对象,但解析和索引都更快。JSONB可以存有序的列表,也可以存带key-value的对象。
-- 学生和各种信息的表
CREATE TABLE students_details (
id SERIAL PRIMARY KEY,
name TEXT,
details JSONB -- 灵活的JSON结构
);
JSONB里的数据例子:
{
"grades": [90, 82, 77],
"address": {
"city": "Berlin",
"zip": "352912"
}
}
所以说,数组就是简单搞定一堆值的列表,而JSONB能玩出花来,适合复杂数据。
数组和JSONB的主要区别
| 特性 | 数组 | JSONB |
|---|---|---|
| 结构类型 | 线性数据结构 | 层级数据结构 |
| 元素类型 | 只能一种数据类型 | 可以多种数据类型 |
| 结构大小 | 固定(线性) | 灵活,可以有列表和对象 |
| 访问速度 | 数据固定时很快 | 复杂查询时慢点 |
| 索引 | 索引支持很好 | 需要用GIN类型索引 |
| 应用场景 | 简单的值列表或数组 | 复杂数据:嵌套对象/列表 |
下面看看实际用起来是啥感觉。
什么时候用数组?
比如你有个图书数据库,每本书可以属于多个类型。这时候数组就很合适。
CREATE TABLE books (
id SERIAL PRIMARY KEY,
title TEXT,
genres TEXT[] -- 类型数组
);
-- 插入一本有多个类型的书
INSERT INTO books (title, genres)
VALUES ('1984', ARRAY['Dystopia', 'Political Fiction', 'Science Fiction']);
数组适合这些场景:
- 你的数据就是纯列表,
- 列表不大而且类型单一(比如字符串或数字),
- 你只需要存和取列表(不搞花里胡哨的操作)。
数组的优点
- 存同类型数据很简单。
- 适合小型列表,比如标签、分类或评分。
什么时候用JSONB?
现在假设你想存更复杂的图书信息,包括类型、ISBN和评分。数组就不行了——这时候该上JSONB了。
CREATE TABLE books_details (
id SERIAL PRIMARY KEY,
title TEXT,
details JSONB -- 书的详细信息,JSONB格式
);
-- 插入一本书的复杂信息
INSERT INTO books_details (title, details)
VALUES (
'1984',
'{"genres": ["Dystopia", "Political Fiction", "Science Fiction"],
"isbn": "9780451524935",
"rating": 8.9}'
);
JSONB适合你需要:
- 存复杂或多样化的数据(数字、字符串、列表、对象),
- 动态加字段,不用改表结构,
- 存嵌套数据(比如地址、属性、配置)。
JSONB的优点
- 超灵活。想加啥key/value都行,不用动表结构。
- 适合存复杂数据,比如API的JSON响应。
数组和JSONB怎么选?
只需要存同类型的列表——用数组。 比如:
-- 存活动参与者ID
CREATE TABLE events (
id SERIAL PRIMARY KEY,
participant_ids INTEGER[]
);
如果数据类型多样或结构复杂——用JSONB更好。 比如:
-- 存客户信息和地址
CREATE TABLE customers (
id SERIAL PRIMARY KEY,
info JSONB
);
数组和JSONB的索引方式不一样。 数组一般用GIN索引,JSONB可以用GIN和BTREE,看你数据结构咋样。
性能
数组在常规查找任务上更快。JSONB慢点,但胜在灵活。如果你只是查元素(比如类型或ID),数组会更快:
-- 用GIN索引搞数组
CREATE INDEX idx_genres ON books USING GIN(genres);
-- 按类型筛选书
SELECT * FROM books WHERE genres @> ARRAY['Science Fiction'];
数据存在性检查
JSONB在按key筛选时更强:
-- 检查有没有"genres"这个key
SELECT * FROM books_details WHERE details ? 'genres';
-- 检查列表里有没有某个元素
SELECT * FROM books_details WHERE details->'genres' ?| ARRAY['Fantasy', 'Dystopia'];
数组可以直接查值:
-- 检查数组里有没有某个元素
SELECT * FROM books WHERE genres @> ARRAY['Fantasy'];
结构的灵活性
如果你数据有复杂嵌套结构,JSONB就无敌了:
{
"genres": ["Fantasy", "Adventure"],
"ratings": {"goodreads": 8.5, "amazon": 4.7}
}
数组做不到,除非你搞表规范化或者加一堆字段。
总之,数组和JSONB不是互相竞争,而是各有用武之地。如果你的数据像个列表——用数组。如果数据复杂、嵌套或者类型多样——放心用JSONB。记得考虑性能和索引方式就行!
GO TO FULL VERSION