在PostgreSQL里用JSON数据其实挺强大的,但就像所有工具一样,用的时候得小心。哪怕是很小的失误,也能让你的查询变成一团乱麻。 今天我们又来聊聊在PostgreSQL里用JSON和JSONB时最常见的错误,还有怎么避免这些坑。
问题1:用JSON而不是JSONB
很多刚入门的小伙伴会误以为JSON类型是存JSON数据的最佳选择。其实JSON在PostgreSQL里就是纯文本存储,这样一来查找或过滤的时候性能会很差。
错误示例:
CREATE TABLE products (
id SERIAL PRIMARY KEY,
details JSON
);
INSERT INTO products (details) VALUES ('{"name": "Laptop", "price": 1000}');
INSERT INTO products (details) VALUES ('{"name": "Laptop", "price": 1000}');
如果你想按price这个key来过滤,速度会比用JSONB慢很多。
怎么改: 如果你打算经常过滤或者查数据,直接用JSONB吧。
CREATE TABLE products (
id SERIAL PRIMARY KEY,
details JSONB
);
问题2:JSONB没加索引
JSONB真的很强大,但如果你不加索引,复杂查询的时候性能会掉得很厉害。
错误示例:假设你有个表,details这一列存了很多JSON对象:
SELECT * FROM products WHERE details->>'name' = 'Laptop';
如果没加索引,数据库就只能全表扫描(full table scan),那速度就很慢了。
怎么改: 给key加个GIN索引,查起来就快多了:
CREATE INDEX idx_details_name ON products USING gin (details jsonb_path_ops);
问题3:取嵌套数据时出错
从嵌套对象或数组里取数据很容易搞混,尤其是你还没搞清楚->和->>这俩操作符的区别时。
错误示例:
SELECT details->'price' FROM products;
这个查询返回的是JSON格式的值,不是字符串("1000"而不是1000)。如果你想要直接拿到值,要用->>:
SELECT details->>'price' FROM products;
问题4:操作符用错了
你可能见过@>这个操作符,觉得:“看起来挺酷的,直接用!”但如果你没搞懂它怎么用,结果可能会很奇怪。
错误示例:
SELECT * FROM products WHERE details @> '{"price": 1000}';
这个查询只有在JSON里的price是数字时才有效。如果price存成了字符串"1000",那啥都查不到。
怎么改: 注意JSON里的数据类型:
SELECT * FROM products WHERE details->>'price' = '1000';
问题5:JSON对象太大
如果你啥都往一个大JSON对象里塞,不做优化,查询会慢得要命。而且,哪怕你只改JSONB里的一小部分,PostgreSQL也得处理整个对象。
怎么改: 如果有些key经常用,直接单独建成表字段。比如:
ALTER TABLE products ADD COLUMN price NUMERIC;
UPDATE products SET price = (details->>'price')::NUMERIC;
这样你就能高效地过滤和排序了,不用每次都拆JSONB。
问题6:每次改都重建整个对象
用jsonb_set()或者jsonb_insert()这些函数时,PostgreSQL会生成一个全新的JSONB对象,这对性能来说挺费劲的。
怎么改: 尽量减少对JSONB的更新。比如,不要频繁地改同一个对象,可以把所有改动合成一次操作:
UPDATE products
SET details = jsonb_set(details, '{price}', '1500'::jsonb);
问题7:没搞懂数组结构
JSONB里的数组也得小心用。假设你有个数组:
{
"tags": ["electronics", "laptop", "sale"]
}
你想查有没有"laptop"这个tag。如果你用错了@>操作符,可能啥都查不到,因为它要的是数组,不是字符串。
错误示例:
SELECT * FROM products WHERE details->'tags' @> '"laptop"';
怎么改: @>操作符里要用正确的格式:
SELECT * FROM products WHERE details->'tags' @> '["laptop"]';
避免错误的小建议
想在用JSONB时少踩坑,可以试试这些做法:
选对数据类型。 如果你数据量大、经常查,直接用JSONB,别用JSON。
加索引。 如果经常查某些key,记得加合适的索引(比如GIN)。
插入前先检查数据。 用校验函数检查数据结构:
DO $$
BEGIN
IF jsonb_typeof('{"price": 1000}'::jsonb->'price') IS DISTINCT FROM 'number' THEN
RAISE EXCEPTION '价格必须是数字';
END IF;
END $$;
优化数据结构。 如果有些key用得特别多,直接单独建成表字段。
多了解操作符和函数。 多看看PostgreSQL官方文档,搞清楚->、->>、@>、?|等操作符和函数的区别。
JSON和JSONB能帮你灵活处理各种复杂数据。关键是选对工具,避开常见的坑,这样你的代码才又快又好维护。
GO TO FULL VERSION