PostgreSQL教程FG138-PG大对象实战:文件上传与存储实现
本文档风哥主要介绍PostgreSQL数据库大对象的实战应用,包括文件上传与存储实现、大对象管理、性能优化等内容,风哥教程参考PostgreSQL官方文档Large
Objects内容编写,适合DBA人员和开发人员在学习和测试中使用,如果要应用于生产环境则需要自行确认。
Part01-基础概念与理论知识
1.1 PostgreSQL数据库大对象概念
PostgreSQL数据库大对象(Large
Objects)是一种用于存储大型二进制数据的机制,支持存储超过1GB的文件。大对象提供了流式访问接口,适合存储图片、视频、文档等大型文件。更多视频教程www.fgedu.net.cn
- 支持存储大型二进制数据(最大可达4TB)
- 提供流式读写接口
- 支持事务性操作
- 存储在专用的系统表中
- 可以通过OID(对象标识符)引用
1.2 PostgreSQL数据库大对象存储原理
PostgreSQL数据库大对象的存储原理:
- 存储位置:大对象数据存储在pg_largeobject系统表中
- 存储方式:数据被分割成固定大小的块(默认2048字节)
- 元数据:大对象的元数据存储在pg_largeobject_metadata表中
- 访问方式:通过OID进行引用和访问
1.3 PostgreSQL数据库大对象适用场景
PostgreSQL数据库大对象的适用场景:
– 存储大型图片和视频文件
– 存储文档和PDF文件
– 存储科学数据和实验结果
– 存储任何超过字段大小限制的二进制数据
– 需要事务支持的文件存储
# 不适用场景
– 频繁访问的小文件(建议使用普通字段)
– 需要文件系统特性的场景
– 需要高并发访问的场景
Part02-生产环境规划与建议
2.1 PostgreSQL数据库大对象存储规划
生产环境中,大对象存储规划建议:
– 为大对象创建专用表空间
– 考虑使用SSD存储提高性能
– 估计存储空间需求,预留足够空间
– 制定数据清理策略
# 表空间规划
CREATE TABLESPACE lobs_ts LOCATION ‘/postgresql/fgdata/lobs’;
# 大对象表规划
CREATE TABLE fgedu_files (
file_id SERIAL PRIMARY KEY,
file_name VARCHAR(255) NOT NULL,
file_size BIGINT NOT NULL,
file_type VARCHAR(100) NOT NULL,
lob_oid OID NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) TABLESPACE lobs_ts;
2.2 PostgreSQL数据库大对象性能考虑
性能考虑:
- 读写性能:大对象读写可能较慢,建议使用预读和缓存
- 事务处理:大对象操作会产生大量WAL日志
- 备份影响:大对象会增加备份大小和时间
- 并发访问:大对象不适合高并发场景
2.3 PostgreSQL数据库大对象安全考虑
安全考虑:
Part03-生产环境项目实施方案
3.1 PostgreSQL数据库大对象管理
3.1.1 PostgreSQL数据库创建和管理大对象
# 创建大对象
SELECT lo_create(0);
# 删除大对象
SELECT lo_unlink(12345);
# 查看大对象信息
SELECT * FROM pg_largeobject_metadata;
# 查看大对象数据块
SELECT * FROM pg_largeobject WHERE loid = 12345;
lo_create
———–
16384
(1 row)
— 删除大对象
lo_unlink
———–
1
(1 row)
— 查看大对象元数据
oid | owner | size | creation
——-+—————-+————–+————
16384 | pgsql | 1048576 | 2026-04-02
(1 row)
3.2 PostgreSQL数据库文件上传实现
3.2.1 PostgreSQL数据库使用psql上传文件
\lo_import ‘/path/to/file.jpg’
# 查看上传的大对象
SELECT oid, size FROM pg_largeobject_metadata;
# 导出大对象到文件
\lo_export 16384 ‘/path/to/output.jpg’
lo_import 16384
oid | size
——-+——–
16384 | 1024000
(1 row)
lo_export
3.2.2 PostgreSQL数据库使用PL/pgSQL处理大对象
CREATE OR REPLACE FUNCTION fgedu_upload_file(p_file_path text, p_file_name text)
RETURNS OID AS $$
DECLARE
l_oid OID;
l_fd INTEGER;
l_buf BYTEA;
l_file TEXT;
BEGIN
— 读取文件内容
l_file := pg_read_file(p_file_path, 0, 1000000000);
— 创建大对象
l_oid := lo_create(0);
— 打开大对象进行写入
l_fd := lo_open(l_oid, 131072); — 131072 = WRITE flag
— 写入数据
lo_write(l_fd, l_file);
— 关闭大对象
PERFORM lo_close(l_fd);
— 记录文件信息
INSERT INTO fgedu_files (file_name, file_size, file_type, lob_oid)
VALUES (p_file_name, length(l_file), substring(p_file_name from ‘\.[^.]+$’), l_oid);
RETURN l_oid;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
# 调用函数上传文件
SELECT fgedu_upload_file(‘/path/to/file.pdf’, ‘document.pdf’);
fgedu_upload_file
——————-
16385
(1 row)
— 查看文件信息
SELECT * FROM fgedu_files;
file_id | file_name | file_size | file_type | lob_oid | created_at
———+————–+———–+———–+———+—————————-
1 | document.pdf | 512000 | .pdf | 16385 | 2026-04-02 10:00:00.000000
(1 row)
3.3 PostgreSQL数据库大对象操作
3.3.1 PostgreSQL数据库大对象读写操作
CREATE OR REPLACE FUNCTION fgedu_read_lob(p_oid OID)
RETURNS BYTEA AS $$
DECLARE
l_fd INTEGER;
l_data BYTEA;
l_buf BYTEA;
l_len INTEGER;
BEGIN
— 打开大对象进行读取
l_fd := lo_open(p_oid, 262144); — 262144 = READ flag
— 读取数据
l_data := ”;
LOOP
l_buf := loread(l_fd, 8192);
EXIT WHEN length(l_buf) = 0;
l_data := l_data || l_buf;
END LOOP;
— 关闭大对象
PERFORM lo_close(l_fd);
RETURN l_data;
END;
$$ LANGUAGE plpgsql;
# 写入大对象内容
CREATE OR REPLACE FUNCTION fgedu_write_lob(p_oid OID, p_data BYTEA)
RETURNS INTEGER AS $$
DECLARE
l_fd INTEGER;
l_len INTEGER;
BEGIN
— 打开大对象进行写入
l_fd := lo_open(p_oid, 131072); — 131072 = WRITE flag
— 写入数据
l_len := lo_write(l_fd, p_data);
— 关闭大对象
PERFORM lo_close(l_fd);
RETURN l_len;
END;
$$ LANGUAGE plpgsql;
Part04-生产案例与实战讲解
4.1 PostgreSQL数据库文件上传系统实现
# file_upload.sh
# from:www.itpux.com.qq113257174.wx:itpux-com
# web: `http://www.fgedu.net.cn`
# 文件上传脚本
# 数据库连接信息
DB_HOST=”localfgedu.net.cn”
DB_PORT=”5432″
DB_NAME=”fgedudb”
DB_USER=”pgsql”
# 上传文件
upload_file() {
local file_path=$1
local file_name=$2
# 检查文件是否存在
if [ ! -f “$file_path” ]; then
echo “文件不存在: $file_path”
return 1
fi
# 获取文件大小
file_size=$(stat -c “%s” “$file_path”)
# 获取文件类型
file_type=$(echo “$file_name” | grep -o “\.[^.]*$”)
# 上传文件到PostgreSQL
result=$(psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME -t -c ”
SELECT lo_import(‘$file_path’);
“)
# 提取OID
oid=$(echo $result | tr -d ‘ ‘)
if [ -z “$oid” ]; then
echo “上传失败”
return 1
fi
# 记录文件信息
psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME -c ”
INSERT INTO fgedu_files (file_name, file_size, file_type, lob_oid)
VALUES (‘$file_name’, $file_size, ‘$file_type’, $oid);
”
echo “文件上传成功,OID: $oid”
return 0
}
# 下载文件
download_file() {
local file_id=$1
local output_path=$2
# 获取大对象OID
oid=$(psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME -t -c ”
SELECT lob_oid FROM fgedu_files WHERE file_id = $file_id;
” | tr -d ‘ ‘)
if [ -z “$oid” ]; then
echo “文件不存在”
return 1
fi
# 导出大对象
psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME -c “\lo_export $oid ‘$output_path'”
echo “文件下载成功: $output_path”
return 0
}
# 主菜单
echo “PostgreSQL文件上传系统”
echo “1. 上传文件”
echo “2. 下载文件”
echo “3. 列出文件”
echo “4. 退出”
read -p “请选择操作: ” choice
case $choice in
1)
read -p “请输入文件路径: ” file_path
read -p “请输入文件名: ” file_name
upload_file “$file_path” “$file_name”
;;
2)
read -p “请输入文件ID: ” file_id
read -p “请输入输出路径: ” output_path
download_file “$file_id” “$output_path”
;;
3)
psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME -c ”
SELECT file_id, file_name, file_size, file_type, created_at
FROM fgedu_files
ORDER BY created_at DESC;
”
;;
4)
echo “退出系统”
exit 0
;;
*)
echo “无效选择”
;;
esac
$ chmod +x file_upload.sh
$ ./file_upload.sh
# 执行结果
PostgreSQL文件上传系统
1. 上传文件
2. 下载文件
3. 列出文件
4. 退出
请选择操作: 1
请输入文件路径: /home/fgedu/document.pdf
请输入文件名: report.pdf
文件上传成功,OID: 16386
$ ./file_upload.sh
PostgreSQL文件上传系统
1. 上传文件
2. 下载文件
3. 列出文件
4. 退出
请选择操作: 3
file_id | file_name | file_size | file_type | created_at
———+————–+———–+———–+—————————-
2 | report.pdf | 768000 | .pdf | 2026-04-02 10:30:00.000000
1 | document.pdf | 512000 | .pdf | 2026-04-02 10:00:00.000000
(2 rows)
4.2 PostgreSQL数据库大对象备份与恢复
大对象的备份与恢复:
pg_dump -h localfgedu.net.cn -p 5432 -U pgsql -d fgedudb -F c -f fgedudb_backup.dump
# 使用pg_restore恢复数据库
pg_restore -h localfgedu.net.cn -p 5432 -U pgsql -d fgedudb fgedudb_backup.dump
# 单独备份大对象
pg_dump -h localfgedu.net.cn -p 5432 -U pgsql -d fgedudb -t pg_largeobject -t pg_largeobject_metadata -F c -f
lobs_backup.dump
# 恢复大对象
pg_restore -h localfgedu.net.cn -p 5432 -U pgsql -d fgedudb lobs_backup.dump
4.3 PostgreSQL数据库大对象性能优化
大对象性能优化策略:
## 1. 存储优化
– 使用专用表空间存储大对象
– 考虑使用SSD存储
– 合理设置表空间参数
## 2. 读写优化
– 使用较大的缓冲区大小
– 实现流式读写
– 避免频繁的小数据读写
## 3. 索引优化
– 为fgedu_files表创建适当的索引
– 优化查询语句
## 4. 配置优化
– 调整shared_buffers参数
– 优化work_mem参数
– 配置适当的maintenance_work_mem
# 具体优化措施
CREATE INDEX idx_fgedu_files_created_at ON fgedu_files(created_at);
CREATE INDEX idx_fgedu_files_file_type ON fgedu_files(file_type);
— 优化查询
EXPLAIN ANALYZE SELECT * FROM fgedu_files WHERE file_type = ‘.pdf’ ORDER BY created_at DESC;
QUERY PLAN
—————————————————————————————————————————-
Sort (cost=18.70..19.20 rows=200 width=104) (actual time=0.032..0.033 rows=2 loops=1)
Sort Key: created_at DESC
Sort Method: quicksort Memory: 25kB
-> Bitmap Heap Scan on fgedu_files (cost=4.30..17.50 rows=200 width=104) (actual time=0.018..0.021 rows=2
loops=1)
Recheck Cond: (file_type = ‘.pdf’::text)
Heap Blocks: exact=1
-> Bitmap Index Scan on idx_fgedu_files_file_type (cost=0.00..4.25 rows=200 width=0) (actual
time=0.012..0.012 rows=2 loops=1)
Index Cond: (file_type = ‘.pdf’::text)
Planning Time: 0.107 ms
Execution Time: 0.056 ms
(10 rows)
Part05-风哥经验总结与分享
5.1 PostgreSQL数据库大对象管理最佳实践
PostgreSQL数据库大对象管理最佳实践:
- 使用专用表空间:为大对象创建独立的表空间
- 建立元数据表:创建专门的表存储大对象的元数据
- 定期清理:删除不再使用的大对象
- 备份策略:制定合理的备份策略
- 性能监控:监控大对象的读写性能
- 权限控制:严格控制大对象的访问权限
5.2 PostgreSQL数据库大对象问题排查
## 1. 大对象损坏
– 检查大对象完整性:SELECT lo_manage(oid) FROM pg_largeobject_metadata;
– 重建损坏的大对象:使用备份恢复
## 2. 性能问题
– 检查大对象大小:SELECT oid, size FROM pg_largeobject_metadata ORDER BY size DESC;
– 分析查询执行计划:EXPLAIN ANALYZE 查询语句
– 监控I/O性能:使用iostat等工具
## 3. 存储空间问题
– 检查大对象占用空间:SELECT pg_size_pretty(pg_total_relation_size(‘pg_largeobject’));
– 清理未使用的大对象:DELETE FROM pg_largeobject WHERE loid NOT IN (SELECT lob_oid FROM fgedu_files);
## 4. 权限问题
– 检查大对象权限:SELECT * FROM information_schema.role_table_grants WHERE table_name = ‘pg_largeobject’;
– 授予必要的权限:GRANT SELECT ON pg_largeobject TO fgedu;
5.3 PostgreSQL数据库大对象工具推荐
PostgreSQL数据库大对象工具:
- psql:使用\lo_import和\lo_export命令
- libpq:使用C语言API操作大对象
- PL/pgSQL:使用lo_*函数操作大对象
- pgAdmin:图形化管理大对象
- 自定义脚本:如本文中的文件上传脚本
本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html
