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相比传统的关系型存储,提供了更大的灵活性,适合存储结构多变的数据。同时,PostgreSQL对JSONB的优化使得它在性能上也能与传统关系型存储相媲美。
1.2 JSONB与JSON的区别
PostgreSQL提供了两种JSON存储类型:JSON和JSONB。它们的主要区别:
– 以文本形式存储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. 对数据一致性要求极高的场景
Part02-生产环境规划与建议
2.1 JSONB存储规划
在使用JSONB前,需要进行详细的存储规划:
1. 数据量评估:估算JSONB数据的大小和增长趋势
2. 访问模式:分析JSONB数据的读写频率和方式
3. 索引策略:确定需要创建的索引类型和字段
4. 存储优化:考虑压缩和分区策略
5. 备份策略:确保JSONB数据的备份和恢复
# 数据量估算
– 单个JSONB文档大小:从几KB到几MB
– 文档数量:从几千到几百万
– 总存储需求:根据单个大小和数量估算
# 访问模式分析
– 读多写少:如产品目录、用户配置等
– 写多读少:如日志数据、事件数据等
– 复杂查询:需要使用JSON路径查询的场景
– 简单查询:基于键值对的查询
2.2 JSONB schema设计
JSONB 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索引
— 为整个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 应用程序集成
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’;
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 查询优化
# 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 存储优化
# 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 常见错误及解决方法
# 错误信息: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监控
# 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;
Part05-风哥经验总结与分享
5.1 JSONB最佳实践
PostgreSQL JSONB最佳实践:
- 合理设计JSON结构:保持JSON结构的一致性和扁平化,减少嵌套层级
- 使用适当的索引:为频繁查询的字段创建适当的索引
- 优化查询语句:使用高效的JSON路径查询,避免全表扫描
- 合理使用JSONB与传统字段:对于频繁查询的字段,使用传统字段
- 监控性能:定期监控JSONB的使用情况,及时发现并解决性能问题
- 备份策略:确保JSONB数据的备份和恢复
- 版本控制:考虑JSON结构的版本演进,确保向后兼容
- 数据验证:在应用层面验证JSON数据的格式和完整性
5.2 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处理
本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html
