1. 首页 > PostgreSQL教程 > 正文

PostgreSQL教程FG280-PG JSONB实战:互联网业务数据存储与查询

本文档风哥主要介绍PostgreSQL JSONB类型的实战应用,包括JSONB的基本操作、索引策略、性能优化等内容。风哥教程参考PostgreSQL官方文档JSON Types内容,适合互联网业务场景中需要灵活存储和查询半结构化数据的应用。更多视频教程www.fgedu.net.cn

Part01-基础概念与理论知识

1.1 PostgreSQL JSONB的概念

JSONB(JSON Binary)是PostgreSQL提供的一种二进制JSON存储类型,用于存储和查询JSON格式的数据。JSONB的主要特点:

  • 以二进制格式存储JSON数据,占用空间更小
  • 支持高效的索引和查询操作
  • 支持复杂的JSON路径查询
  • 支持JSON数据的修改和更新
  • 兼容标准JSON格式
JSONB的优势:

JSONB相比传统的关系型存储,提供了更大的灵活性,适合存储结构多变的数据。同时,PostgreSQL对JSONB的优化使得它在性能上也能与传统关系型存储相媲美。

1.2 JSONB与JSON的区别

PostgreSQL提供了两种JSON存储类型:JSON和JSONB。它们的主要区别:

# JSON类型
– 以文本形式存储JSON数据
– 保留原始格式和空格
– 存储时不做任何处理
– 查询时需要解析JSON文本
– 性能相对较低

# JSONB类型
– 以二进制格式存储JSON数据
– 移除多余空格和重复键
– 存储时进行解析和优化
– 查询时无需重新解析
– 性能更高
– 支持索引

# 选择建议
– 对于仅存储和读取的场景,两者差异不大
– 对于需要频繁查询或更新的场景,推荐使用JSONB
– 对于需要保留原始JSON格式的场景,使用JSON

1.3 JSONB适用场景

PostgreSQL JSONB适用于以下场景:

# 适用场景
1. 互联网业务数据:如用户配置、产品属性、订单详情等
2. 半结构化数据:结构多变但有一定规律的数据
3. 日志数据:如应用日志、系统日志等
4. 配置数据:如应用配置、系统参数等
5. 临时数据:需要灵活结构的数据
6. 与NoSQL数据的集成:如从MongoDB迁移的数据

# 不适用场景
1. 高度结构化且固定的数据(使用传统关系型表更合适)
2. 需要复杂事务支持的数据
3. 需要频繁JOIN操作的数据
4. 对数据一致性要求极高的场景

风哥提示:JSONB是PostgreSQL的一个强大特性,特别适合互联网业务中结构多变的数据存储需求。在设计数据模型时,应根据数据的结构特点和访问模式,合理选择使用JSONB还是传统关系型存储。

Part02-生产环境规划与建议

2.1 JSONB存储规划

在使用JSONB前,需要进行详细的存储规划:

# 存储规划要点
1. 数据量评估:估算JSONB数据的大小和增长趋势
2. 访问模式:分析JSONB数据的读写频率和方式
3. 索引策略:确定需要创建的索引类型和字段
4. 存储优化:考虑压缩和分区策略
5. 备份策略:确保JSONB数据的备份和恢复

# 数据量估算
– 单个JSONB文档大小:从几KB到几MB
– 文档数量:从几千到几百万
– 总存储需求:根据单个大小和数量估算

# 访问模式分析
– 读多写少:如产品目录、用户配置等
– 写多读少:如日志数据、事件数据等
– 复杂查询:需要使用JSON路径查询的场景
– 简单查询:基于键值对的查询

2.2 JSONB schema设计

JSONB schema设计建议:

# Schema设计原则
1. 一致性:保持JSON结构的一致性,便于查询和索引
2. 扁平化:尽量扁平化JSON结构,减少嵌套层级
3. 类型一致性:同一字段使用一致的数据类型
4. 命名规范:使用统一的命名规范
5. 版本控制:考虑JSON结构的版本演进

# 示例Schema设计
{
“id”: 1,
“name”: “Product Name”,
“price”: 99.99,
“attributes”: {
“color”: “red”,
“size”: “M”,
“weight”: 0.5
},
“tags”: [“electronics”, “gadget”],
“created_at”: “2026-04-02T10:00:00Z”
}

# 嵌套层级建议
– 建议不超过3-4层嵌套
– 超过嵌套层级限制时,考虑拆分为多个JSONB字段

# 数据类型建议
– 数字:使用数值类型,不使用字符串
– 日期:使用ISO 8601格式
– 布尔值:使用true/false,不使用”true”/”false”

2.3 性能考虑因素

JSONB性能考虑因素:

风哥教程针对风哥教程针对风哥教程针对生产环境建议:

  • 索引策略:为频繁查询的JSON字段创建适当的索引
  • 查询优化:使用高效的JSON路径查询,避免全表扫描
  • 存储优化:合理设置JSONB字段的大小,避免过度存储
  • 内存配置:增加shared_buffers以提高JSONB数据的缓存效率
  • 连接池:使用连接池减少连接开销

Part03-生产环境项目实施方案

3.1 JSONB基本操作

3.1.1 JSONB数据的插入与更新

# 创建表
CREATE TABLE fgedu_products (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
data JSONB NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

# 插入JSONB数据
INSERT INTO fgedu_products (name, data)
VALUES (
‘Smartphone’,
‘{
“brand”: “Apple”,
“model”: “iPhone 15”,
“price”: 999.99,
“specs”: {
“display”: “6.1 inches”,
“storage”: “128GB”,
“camera”: “48MP”
},
“tags”: [“electronics”, “smartphone”]
}’
);

# 更新JSONB数据
— 更新整个JSONB字段
UPDATE fgedu_products
SET data = ‘{
“brand”: “Apple”,
“model”: “iPhone 15 Pro”,
“price”: 1199.99,
“specs”: {
“display”: “6.1 inches”,
“storage”: “256GB”,
“camera”: “48MP”
},
“tags”: [“electronics”, “smartphone”, “pro”]
}’
WHERE id = 1;

— 更新JSONB中的特定字段
UPDATE fgedu_products
SET data = data || ‘{“price”: 1099.99}’::jsonb
WHERE id = 1;

— 使用jsonb_set更新嵌套字段
UPDATE fgedu_products
SET data = jsonb_set(data, ‘{specs, storage}’, ‘”512GB”‘)
WHERE id = 1;

— 添加数组元素
UPDATE fgedu_products
SET data = jsonb_set(data, ‘{tags}’, data->’tags’ || ‘”premium”‘::jsonb)
WHERE id = 1;

3.1.2 JSONB数据的查询

# 基本查询
— 查询所有产品
SELECT * FROM fgedu_products;

— 查询特定字段
SELECT id, name, data->’brand’ AS brand, data->’price’ AS price
FROM fgedu_products;

— 使用->>获取文本值
SELECT id, name, data->>’brand’ AS brand, data->>’price’ AS price
FROM fgedu_products;

# 条件查询
— 基于顶层字段的查询
SELECT * FROM fgedu_products WHERE data->>’brand’ = ‘Apple’;

— 基于嵌套字段的查询
SELECT * FROM fgedu_products WHERE data->’specs’->>’storage’ = ‘256GB’;

— 基于数组元素的查询
SELECT * FROM fgedu_products WHERE data->’tags’ @> ‘”smartphone”‘::jsonb;

— 基于数值范围的查询
SELECT * FROM fgedu_products WHERE (data->>’price’)::numeric > 1000;

# JSON路径查询
— 使用JSON路径查询
SELECT * FROM fgedu_products WHERE data @> ‘{“specs”: {“camera”: “48MP”}}’;

— 使用jsonb_path_exists
SELECT * FROM fgedu_products
WHERE jsonb_path_exists(data, ‘$.specs.storage ? (@ == “256GB”)’);

— 使用jsonb_path_query
SELECT id, name, jsonb_path_query(data, ‘$.specs.*’) AS specs
FROM fgedu_products;

3.2 JSONB索引策略

3.2.1 创建JSONB索引

# 创建GIN索引
— 为整个JSONB字段创建GIN索引
CREATE INDEX idx_fgedu_products_data ON fgedu_products USING GIN (data);

— 为特定JSON路径创建GIN索引
CREATE INDEX idx_fgedu_products_brand ON fgedu_products USING GIN ((data->’brand’));

— 为嵌套字段创建GIN索引
CREATE INDEX idx_fgedu_products_storage ON fgedu_products USING GIN ((data->’specs’->’storage’));

# 创建BTREE索引
— 为JSONB字段中的文本值创建BTREE索引
CREATE INDEX idx_fgedu_products_brand_btree ON fgedu_products ((data->>’brand’));

— 为JSONB字段中的数值创建BTREE索引
CREATE INDEX idx_fgedu_products_price_btree ON fgedu_products (((data->>’price’)::numeric));

# 创建表达式索引
— 为计算表达式创建索引
CREATE INDEX idx_fgedu_products_tags_count ON fgedu_products ((jsonb_array_length(data->’tags’)));

# 索引类型选择建议
– 对于包含多个键值对的JSONB字段:使用GIN索引
– 对于单个字段的等值查询:使用BTREE索引
– 对于范围查询:使用BTREE索引
– 对于数组包含查询:使用GIN索引

3.2.2 索引使用与优化

# 查看索引使用情况
— 执行EXPLAIN分析查询计划
EXPLAIN ANALYZE SELECT * FROM fgedu_products WHERE data->>’brand’ = ‘Apple’;

— 输出示例
Nested Loop (cost=0.29..8.31 rows=1 width=104) (actual time=0.023..0.024 rows=1 loops=1)
-> Index Scan using idx_fgedu_products_brand_btree on fgedu_products (cost=0.29..4.30 rows=1 width=104) (actual time=0.019..0.020 rows=1 loops=1)
Index Cond: ((data ->> ‘brand’::text) = ‘Apple’::text)
-> Seq Scan on fgedu_products (cost=0.00..4.01 rows=1 width=0) (actual time=0.002..0.002 rows=1 loops=1)
Filter: ((data ->> ‘brand’::text) = ‘Apple’::text)
Rows Removed by Filter: 0
Planning Time: 0.069 ms
Execution Time: 0.041 ms

# 索引优化建议
– 只为频繁查询的字段创建索引
– 避免为大型JSONB字段创建过多索引
– 定期维护索引(VACUUM ANALYZE)
– 监控索引大小和性能

# 复合索引
— 创建复合索引
CREATE INDEX idx_fgedu_products_brand_price ON fgedu_products ((data->>’brand’), ((data->>’price’)::numeric));

— 使用复合索引的查询
SELECT * FROM fgedu_products
WHERE data->>’brand’ = ‘Apple’ AND (data->>’price’)::numeric > 1000;

3.3 应用集成方案

3.3.1 应用程序集成

# Python应用集成示例
import psycopg2
import json

# 连接数据库
conn = psycopg2.connect(
fgedudb=”fgedudb”,
fgedu=”fgedu”,
password=”password”,
fgedu.net.cn=”localfgedu.net.cn”
)
cur = conn.cursor()

# 插入JSONB数据
def insert_product(name, product_data):
cur.execute(
“INSERT INTO fgedu_products (name, data) VALUES (%s, %s)”,
(name, json.dumps(product_data))
)
conn.commit()

# 查询JSONB数据
def get_products_by_brand(brand):
cur.execute(
“SELECT id, name, data FROM fgedu_products WHERE data->>’brand’ = %s”,
(brand,)
)
return cur.fetchall()

# 更新JSONB数据
def update_product_price(product_id, new_price):
cur.execute(
“UPDATE fgedu_products SET data = data || %s::jsonb WHERE id = %s”,
(json.dumps({“price”: new_price}), product_id)
)
conn.commit()

# 使用示例
product_data = {
“brand”: “Samsung”,
“model”: “Galaxy S24”,
“price”: 899.99,
“specs”: {
“display”: “6.2 inches”,
“storage”: “128GB”,
“camera”: “50MP”
},
“tags”: [“electronics”, “smartphone”]
}

insert_product(“Galaxy S24”, product_data)
print(“Product inserted successfully”)

products = get_products_by_brand(“Samsung”)
for product in products:
print(f”ID: {product[0]}, Name: {product[1]}, Data: {product[2]}”)

update_product_price(products[0][0], 799.99)
print(“Product price updated successfully”)

# 关闭连接
cur.close()
conn.close()

3.3.2 JSONB与关系型数据的结合

# 混合存储模式
— 创建包含JSONB和传统字段的表
CREATE TABLE fgedu_fgedus (
id SERIAL PRIMARY KEY,
fgeduname VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
profile JSONB,
settings JSONB,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

— 插入数据
INSERT INTO fgedu_fgedus (fgeduname, email, profile, settings)
VALUES (
‘fgedu1’,
‘fgedu1@fgedu.net.cn’,
‘{“name”: “John Doe”, “age”: 30, “address”: {“city”: “New York”, “zip”: “10001”}}’,
‘{“notifications”: true, “theme”: “dark”, “language”: “en”}’
);

— 查询混合数据
SELECT id, fgeduname, email, profile->>’name’ AS name, settings->>’theme’ AS theme
FROM fgedu_fgedus
WHERE profile->>’city’ = ‘New York’;

— 索引混合字段
CREATE INDEX idx_fgedu_fgedus_city ON fgedu_fgedus ((profile->>’city’));
CREATE INDEX idx_fgedu_fgedus_theme ON fgedu_fgedus ((settings->>’theme’));

# 关联查询
— 创建订单表
CREATE TABLE fgedu_orders (
id SERIAL PRIMARY KEY,
fgedu_id INTEGER REFERENCES fgedu_fgedus(id),
order_data JSONB,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

— 插入订单数据
INSERT INTO fgedu_orders (fgedu_id, order_data)
VALUES (
1,
‘{“items”: [{“product_id”: 1, “quantity”: 2, “price”: 99.99}, {“product_id”: 2, “quantity”: 1, “price”: 49.99}], “total”: 249.97}’
);

— 关联查询
SELECT u.fgeduname, o.id, o.order_data->>’total’ AS total
FROM fgedu_fgedus u
JOIN fgedu_orders o ON u.id = o.fgedu_id
WHERE u.profile->>’city’ = ‘New York’;

风哥提示:在应用中使用JSONB时,应根据数据的访问模式和查询需求,合理设计JSON结构和索引策略。对于频繁查询的字段,建议创建适当的索引以提高查询性能。学习交流加群风哥微信: itpux-com

Part04-生产案例与实战讲解

4.1 JSONB实战案例

4.1.1 电商产品目录

# 场景:电商平台产品目录,需要存储多样化的产品属性

# 1. 数据库设计
CREATE TABLE fgedu_products (
id SERIAL PRIMARY KEY,
sku VARCHAR(50) UNIQUE NOT NULL,
name VARCHAR(255) NOT NULL,
category VARCHAR(100) NOT NULL,
data JSONB NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

# 2. 创建索引
CREATE INDEX idx_fgedu_products_category ON fgedu_products (category);
CREATE INDEX idx_fgedu_products_data ON fgedu_products USING GIN (data);
CREATE INDEX idx_fgedu_products_brand ON fgedu_products ((data->>’brand’));
CREATE INDEX idx_fgedu_products_price ON fgedu_products (((data->>’price’)::numeric));

# 3. 插入产品数据
INSERT INTO fgedu_products (sku, name, category, data)
VALUES
(‘PROD001’, ‘Smartphone’, ‘Electronics’, ‘{
“brand”: “Apple”,
“model”: “iPhone 15”,
“price”: 999.99,
“specs”: {
“display”: “6.1 inches”,
“storage”: “128GB”,
“camera”: “48MP”,
“battery”: “4000mAh”
},
“colors”: [“black”, “white”, “red”],
“stock”: 100
}’),
(‘PROD002’, ‘Laptop’, ‘Electronics’, ‘{
“brand”: “Dell”,
“model”: “XPS 13”,
“price”: 1299.99,
“specs”: {
“display”: “13.3 inches”,
“processor”: “Intel i7”,
“ram”: “16GB”,
“storage”: “512GB SSD”
},
“colors”: [“silver”, “carbon black”],
“stock”: 50
}’),
(‘PROD003’, ‘T-Shirt’, ‘Clothing’, ‘{
“brand”: “Nike”,
“model”: “Sportswear”,
“price”: 29.99,
“specs”: {
“material”: “cotton”,
“size”: [“S”, “M”, “L”, “XL”],
“fit”: “regular”
},
“colors”: [“black”, “white”, “blue”],
“stock”: 200
}’);

# 4. 查询示例
— 按类别查询产品
SELECT id, sku, name, data->>’price’ AS price
FROM fgedu_products
WHERE category = ‘Electronics’;

— 按品牌查询产品
SELECT id, sku, name, data->>’model’ AS model
FROM fgedu_products
WHERE data->>’brand’ = ‘Apple’;

— 按价格范围查询产品
SELECT id, sku, name, data->>’price’ AS price
FROM fgedu_products
WHERE (data->>’price’)::numeric BETWEEN 100 AND 1000;

— 按规格查询产品
SELECT id, sku, name, data->>’brand’ AS brand
FROM fgedu_products
WHERE data->’specs’->>’storage’ = ‘128GB’;

— 按颜色查询产品
SELECT id, sku, name, data->>’brand’ AS brand
FROM fgedu_products
WHERE data->’colors’ @> ‘”black”‘::jsonb;

# 5. 更新产品数据
— 更新库存
UPDATE fgedu_products
SET data = jsonb_set(data, ‘{stock}’, ’95’)
WHERE sku = ‘PROD001’;

— 添加新颜色
UPDATE fgedu_products
SET data = jsonb_set(data, ‘{colors}’, data->’colors’ || ‘”green”‘::jsonb)
WHERE sku = ‘PROD003’;

— 更新价格
UPDATE fgedu_products
SET data = data || ‘{“price”: 899.99}’::jsonb
WHERE sku = ‘PROD001’;

4.1.2 用户配置管理

# 场景:用户配置管理,需要存储用户的个性化设置

# 1. 数据库设计
CREATE TABLE fgedu_fgedu_settings (
id SERIAL PRIMARY KEY,
fgedu_id INTEGER REFERENCES fgedu_fgedus(id),
settings JSONB NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

# 2. 创建索引
CREATE INDEX idx_fgedu_fgedu_settings_fgedu_id ON fgedu_fgedu_settings (fgedu_id);
CREATE INDEX idx_fgedu_fgedu_settings_settings ON fgedu_fgedu_settings USING GIN (settings);

# 3. 插入用户设置
INSERT INTO fgedu_fgedu_settings (fgedu_id, settings)
VALUES
(1, ‘{
“notifications”: {
“email”: true,
“sms”: false,
“push”: true
},
“preferences”: {
“theme”: “dark”,
“language”: “en”,
“timezone”: “UTC”
},
“privacy”: {
“public_profile”: true,
“show_email”: false,
“show_phone”: false
}
}’),
(2, ‘{
“notifications”: {
“email”: true,
“sms”: true,
“push”: false
},
“preferences”: {
“theme”: “light”,
“language”: “zh”,
“timezone”: “Asia/Shanghai”
},
“privacy”: {
“public_profile”: false,
“show_email”: true,
“show_phone”: true
}
}’);

# 4. 查询示例
— 获取用户的通知设置
SELECT fgedu_id, settings->’notifications’ AS notifications
FROM fgedu_fgedu_settings
WHERE fgedu_id = 1;

— 查询使用深色主题的用户
SELECT fgedu_id
FROM fgedu_fgedu_settings
WHERE settings->’preferences’->>’theme’ = ‘dark’;

— 查询启用邮件通知的用户
SELECT fgedu_id
FROM fgedu_fgedu_settings
WHERE settings->’notifications’->>’email’ = ‘true’;

# 5. 更新用户设置
— 更新主题设置
UPDATE fgedu_fgedu_settings
SET settings = jsonb_set(settings, ‘{preferences, theme}’, ‘”light”‘)
WHERE fgedu_id = 1;

— 更新通知设置
UPDATE fgedu_fgedu_settings
SET settings = jsonb_set(settings, ‘{notifications, push}’, ‘false’)
WHERE fgedu_id = 1;

— 添加新的设置项
UPDATE fgedu_fgedu_settings
SET settings = settings || ‘{“accessibility”: {“font_size”: “medium”, “high_contrast”: false}}’::jsonb
WHERE fgedu_id = 1;

4.2 JSONB性能优化

4.2.1 查询优化

# JSONB查询优化

# 1. 使用适当的索引
— 为频繁查询的字段创建索引
CREATE INDEX idx_fgedu_products_price ON fgedu_products (((data->>’price’)::numeric));

— 使用索引的查询
EXPLAIN ANALYZE SELECT * FROM fgedu_products WHERE (data->>’price’)::numeric > 1000;

# 2. 避免全表扫描
— 不好的查询(可能导致全表扫描)
SELECT * FROM fgedu_products WHERE data @> ‘{“specs”: {“camera”: “48MP”}}’;

— 好的查询(使用索引)
CREATE INDEX idx_fgedu_products_camera ON fgedu_products ((data->’specs’->>’camera’));
SELECT * FROM fgedu_products WHERE data->’specs’->>’camera’ = ’48MP’;

# 3. 使用JSON路径表达式
— 使用jsonb_path_exists进行复杂查询
SELECT * FROM fgedu_products
WHERE jsonb_path_exists(data, ‘$.specs.storage ? (@ like_regex “128GB|256GB”)’);

# 4. 限制返回数据
— 只返回需要的字段
SELECT id, name, data->>’price’ AS price
FROM fgedu_products
WHERE data->>’brand’ = ‘Apple’;

# 5. 使用LIMIT和OFFSET
— 分页查询
SELECT * FROM fgedu_products
WHERE data->>’category’ = ‘Electronics’
ORDER BY (data->>’price’)::numeric DESC
LIMIT 10 OFFSET 0;

4.2.2 存储优化

# JSONB存储优化

# 1. 压缩JSON数据
— PostgreSQL会自动压缩JSONB数据
— 可以通过pg_column_size查看存储大小
SELECT id, name, pg_column_size(data) AS size
FROM fgedu_products
ORDER BY size DESC;

# 2. 扁平化JSON结构
— 不好的结构(深层嵌套)
{
“fgedu”: {
“profile”: {
“address”: {
“city”: “New York”
}
}
}
}

— 好的结构(扁平化)
{
“fgedu_profile_address_city”: “New York”
}

# 3. 避免存储重复数据
— 不好的做法(存储重复数据)
{
“product”: {
“name”: “Smartphone”,
“category”: “Electronics”,
“brand”: “Apple”,
“model”: “iPhone 15”
},
“order”: {
“product_name”: “Smartphone”,
“product_category”: “Electronics”
}
}

— 好的做法(避免重复)
{
“product”: {
“id”: 1,
“name”: “Smartphone”,
“category”: “Electronics”,
“brand”: “Apple”,
“model”: “iPhone 15”
},
“order”: {
“product_id”: 1,
“quantity”: 2
}
}

# 4. 合理使用JSONB与传统字段
— 对于频繁查询的字段,使用传统字段
— 对于结构多变的字段,使用JSONB
CREATE TABLE fgedu_products (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL, — 传统字段
price DECIMAL(10,2) NOT NULL, — 传统字段
category VARCHAR(100) NOT NULL, — 传统字段
attributes JSONB, — JSONB字段
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

4.3 JSONB常见问题处理

4.3.1 常见错误及解决方法

# 1. JSON格式错误
# 错误信息:ERROR: invalid input syntax for type json
# 解决方法:
– 确保JSON格式正确
– 使用JSON验证工具检查JSON格式
– 使用jsonb_validate函数验证JSON

# 2. 索引未使用
# 错误信息:查询执行计划显示全表扫描
# 解决方法:
– 确保创建了适当的索引
– 检查查询条件是否使用了索引字段
– 运行VACUUM ANALYZE更新统计信息

# 3. JSONB字段过大
# 错误信息:ERROR: row is too big
# 解决方法:
– 拆分JSONB字段为多个字段
– 减少JSONB字段的大小
– 考虑使用大对象存储大型JSON数据

# 4. 性能问题
# 错误信息:查询执行缓慢
# 解决方法:
– 创建适当的索引
– 优化查询语句
– 考虑使用物化视图
– 调整数据库参数

# 5. JSON路径查询错误
# 错误信息:ERROR: jsonpath syntax error
# 解决方法:
– 检查JSON路径语法
– 使用正确的JSON路径表达式
– 风哥教程参考PostgreSQL官方文档中的JSON路径语法

4.3.2 JSONB监控

# JSONB监控

# 1. 监控JSONB字段大小
SELECT table_name, column_name, avg(pg_column_size(column_name)) as avg_size
FROM information_schema.columns
JOIN pg_stat_fgedu_tables ON table_name = relname
WHERE data_type = ‘jsonb’
GROUP BY table_name, column_name;

# 2. 监控JSONB查询性能
SELECT query, calls, total_exec_time, mean_exec_time
FROM pg_stat_statements
WHERE query LIKE ‘%jsonb%’ OR query LIKE ‘%data->%’
ORDER BY total_exec_time DESC
LIMIT 10;

# 3. 监控索引使用情况
SELECT indexrelid::regclass AS index_name,
relid::regclass AS table_name,
idx_scan,
idx_tup_read,
idx_tup_fetch
FROM pg_stat_fgedu_indexes
JOIN pg_stat_fgedu_tables ON pg_stat_fgedu_indexes.relid = pg_stat_fgedu_tables.relid
WHERE indexrelid::regclass::text LIKE ‘%jsonb%’ OR
indexrelid::regclass::text LIKE ‘%data%’
ORDER BY idx_scan DESC;

# 4. 监控JSONB更新操作
SELECT query, calls, total_exec_time
FROM pg_stat_statements
WHERE query LIKE ‘%UPDATE%jsonb%’ OR query LIKE ‘%jsonb_set%’
ORDER BY total_exec_time DESC
LIMIT 10;

风哥教程针对风哥教程针对风哥教程针对生产环境建议:定期监控JSONB的使用情况,包括存储大小、查询性能、索引使用等,及时发现并解决性能问题。同时,根据业务需求的变化,调整JSON结构和索引策略,确保系统的性能和可维护性。更多学习教程公众号风哥教程itpux_com

Part05-风哥经验总结与分享

5.1 JSONB最佳实践

PostgreSQL JSONB最佳实践:

  • 合理设计JSON结构:保持JSON结构的一致性和扁平化,减少嵌套层级
  • 使用适当的索引:为频繁查询的字段创建适当的索引
  • 优化查询语句:使用高效的JSON路径查询,避免全表扫描
  • 合理使用JSONB与传统字段:对于频繁查询的字段,使用传统字段
  • 监控性能:定期监控JSONB的使用情况,及时发现并解决性能问题
  • 备份策略:确保JSONB数据的备份和恢复
  • 版本控制:考虑JSON结构的版本演进,确保向后兼容
  • 数据验证:在应用层面验证JSON数据的格式和完整性

5.2 JSONB实施检查清单

# PostgreSQL JSONB实施检查清单

## 设计阶段
– [ ] 评估数据结构和访问模式
– [ ] 确定使用JSONB的必要性
– [ ] 设计合理的JSON结构
– [ ] 规划索引策略

## 实施阶段
– [ ] 创建包含JSONB字段的表
– [ ] 创建适当的索引
– [ ] 实现JSONB数据的插入和更新逻辑
– [ ] 测试JSONB查询性能

## 优化阶段
– [ ] 分析查询执行计划
– [ ] 优化索引策略
– [ ] 调整JSON结构
– [ ] 监控性能指标

## 维护阶段
– [ ] 定期清理无用数据
– [ ] 维护索引(VACUUM ANALYZE)
– [ ] 监控JSONB存储大小
– [ ] 备份JSONB数据

## 安全阶段
– [ ] 验证JSON数据的完整性
– [ ] 防止JSON注入攻击
– [ ] 设置适当的访问权限
– [ ] 加密敏感JSON数据

5.3 JSONB工具推荐

PostgreSQL JSONB相关工具推荐:

  • pgAdmin:图形化工具,支持JSONB数据的查看和编辑
  • psql:命令行工具,支持JSONB数据的操作
  • PostgreSQL JSON Functions:内置的JSON处理函数
  • JSONPath:JSON路径查询语言
  • jq:命令行JSON处理工具,可用于验证和转换JSON数据
  • Python JSON库:用于应用层面的JSON处理
  • Node.js JSON库:用于应用层面的JSON处理
风哥提示:JSONB是PostgreSQL的一个强大特性,特别适合互联网业务中结构多变的数据存储需求。在使用JSONB时,应根据具体的业务需求和性能要求,合理设计数据结构和索引策略,以获得最佳的性能和可维护性。from PostgreSQL视频:www.itpux.com

持续改进:JSONB的使用是一个不断优化的过程,需要根据业务需求的变化和数据量的增长,不断调整和优化JSON结构、索引策略和查询语句。建议定期回顾JSONB的使用情况,评估其性能和可维护性,及时进行优化和调整。

本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html

联系我们

在线咨询:点击这里给我发消息

微信号:itpux-com

工作日:9:30-18:30,节假日休息