1. 首页 > PostgreSQL教程 > 正文

PostgreSQL教程FG131-PG大对象:创建/存储/读取/删除实操

本文档风哥主要介绍PostgreSQL的大对象(Large Objects)功能,包括创建、存储、读取、删除等操作,风哥教程参考PostgreSQL官方文档Large Objects内容,适合开发人员在学习和测试中使用,如果要应用于生产环境则需要自行确认。

Part01-基础概念与理论知识

1.1 大对象概述

PostgreSQL的大对象(Large Objects,简称LO)是一种用于存储大型二进制数据的数据类型,可以存储最大4TB的数据。大对象适用于存储图片、音频、视频、文档等大型文件。更多视频教程www.fgedu.net.cn

大对象特点:

  • 支持最大4TB的数据存储
  • 支持随机访问
  • 支持事务
  • 支持权限控制
  • 支持增量读写

1.2 大对象类型

PostgreSQL提供两种大对象类型:

from oracle:www.itpux.com

  • OID(Object Identifier):大对象的唯一标识符,存储在pg_largeobject系统表中
  • BYTEA:二进制数据类型,适合存储较小的二进制数据(< 1GB)
— 大对象类型对比

— OID类型
— 优点:支持大文件(最大4TB),支持流式读写
— 缺点:需要特殊API操作,管理复杂

— BYTEA类型
— 优点:使用简单,与普通列一样操作
— 缺点:有1GB限制,不适合超大文件

— 选择建议:
— 文件 < 100MB:使用BYTEA -- 文件 >= 100MB:使用OID大对象

1.3 大对象存储机制

大对象的存储机制:

  • 大对象数据存储在pg_largeobject系统表中
  • 每个大对象被分割成多个数据块(默认2KB)
  • 每个数据块有唯一的标识符(OID + 页号)
  • 大对象的元数据存储在pg_largeobject_metadata系统表中
风哥提示:大对象适合存储大型二进制文件,但管理相对复杂,需要根据实际需求选择合适的大对象类型。学习交流加群风哥微信: itpux-com

Part02-生产环境规划与建议

2.1 大对象设计

大对象的设计要点:

— 大对象设计要点

— 1. 表结构设计
— 创建包含大对象的表
CREATE TABLE fgedu_documents (
id SERIAL PRIMARY KEY,
filename VARCHAR(255) NOT NULL,
file_size BIGINT NOT NULL,
file_type VARCHAR(50) NOT NULL,
file_data OID, — 大对象引用
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

— 2. 索引设计
— 为大对象表创建索引
CREATE INDEX idx_fgedu_documents_filename ON fgedu_documents(filename);
CREATE INDEX idx_fgedu_documents_file_type ON fgedu_documents(file_type);
CREATE INDEX idx_fgedu_documents_created_at ON fgedu_documents(created_at);

— 3. 触发器设计
— 创建触发器,在删除记录时自动删除大对象
CREATE OR REPLACE FUNCTION delete_large_object()
RETURNS TRIGGER AS $$
BEGIN
IF OLD.file_data IS NOT NULL THEN
PERFORM lo_unlink(OLD.file_data);
END IF;
RETURN OLD;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_delete_large_object
BEFORE DELETE ON fgedu_documents
FOR EACH ROW
EXECUTE FUNCTION delete_large_object();

2.2 大对象安全

大对象的安全考虑:

  • 权限控制:使用GRANT/REVOKE控制大对象的访问权限
  • 数据加密:对敏感数据进行加密存储
  • 访问审计:记录大对象的访问日志
  • 备份恢复:确保大对象能够正确备份和恢复
— 大对象权限控制

— 授予大对象权限
GRANT SELECT ON fgedu_documents TO fgedu_fgedu;
GRANT INSERT ON fgedu_documents TO fgedu_fgedu;
GRANT UPDATE ON fgedu_documents TO fgedu_fgedu;

— 授予大对象操作权限
— 注意:大对象权限需要在数据库级别授予
GRANT SELECT ON pg_largeobject TO fgedu_fgedu;
GRANT UPDATE ON pg_largeobject TO fgedu_fgedu;

— 撤销权限
REVOKE ALL ON fgedu_documents FROM fgedu_fgedu;

2.3 大对象性能

大对象的性能优化:

  • 存储优化:使用TOAST存储大对象数据
  • 读取优化:使用流式读取,避免一次性加载大对象
  • 写入优化:使用批量写入,减少IO操作
  • 缓存优化:合理配置shared_buffers
风哥教程针对风哥教程针对风哥教程针对生产环境建议:在生产环境中,建议对大对象进行适当的分区和索引,以提高查询性能。同时要注意监控大对象的存储使用情况,及时清理不再需要的大对象。学习交流加群风哥QQ113257174

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

3.1 大对象创建

3.1.1 使用SQL创建大对象

— 使用SQL创建大对象

— 1. 创建空的大对象
SELECT lo_create(0);
— 返回:16384(OID值)

— 2. 创建大对象并导入文件
SELECT lo_import(‘/path/to/file.pdf’);
— 返回:16385(OID值)

— 3. 创建大对象并导出到文件
SELECT lo_export(16385, ‘/path/to/output.pdf’);
— 返回:1(成功)

— 4. 删除大对象
SELECT lo_unlink(16385);
— 返回:1(成功)

3.1.2 使用libpq创建大对象

// 使用libpq创建大对象
// 文件:lo_create.c
// from:www.itpux.com.qq113257174.wx:itpux-com
// web: http://www.fgedu.net.cn

#include
#include
#include #include

int main() {
const char *conninfo = “fgedu.net.cn=localfgedu.net.cn port=5432 fgedudb=fgedudb fgedu=pgsql password=postgres_password”;
PGconn *conn = PQconnectdb(conninfo);

if (PQstatus(conn) != CONNECTION_OK) {
fprintf(stderr, “连接失败: %s\n”, PQerrorMessage(conn));
PQfinish(conn);
return 1;
}

// 创建大对象
Oid lobjId = lo_creat(conn, INV_READ | INV_WRITE);
if (lobjId == 0) {
fprintf(stderr, “创建大对象失败: %s\n”, PQerrorMessage(conn));
PQfinish(conn);
return 1;
}

printf(“大对象创建成功,OID: %u\n”, lobjId);

// 打开大对象进行写入
int lobj_fd = lo_open(conn, lobjId, INV_WRITE);
if (lobj_fd < 0) { fprintf(stderr, "打开大对象失败: %s\n", PQerrorMessage(conn)); PQfinish(conn); return 1; } // 写入数据 const char *data = "这是一个大对象测试数据"; int written = lo_write(conn, lobj_fd, data, strlen(data)); if (written < 0) { fprintf(stderr, "写入大对象失败: %s\n", PQerrorMessage(conn)); lo_close(conn, lobj_fd); PQfinish(conn); return 1; } printf("写入 %d 字节数据\n", written); // 关闭大对象 lo_close(conn, lobj_fd); // 将大对象OID插入到表中 char query[256]; sprintf(query, "INSERT INTO fgedu_documents (filename, file_size, file_type, file_data) VALUES ('test.txt', %d, 'text/plain', %u)", written, lobjId); PGresult *res = PQexec(conn, query); if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "插入记录失败: %s\n", PQerrorMessage(conn)); PQclear(res); lo_unlink(conn, lobjId); PQfinish(conn); return 1; } PQclear(res); printf("大对象记录插入成功\n"); PQfinish(conn); return 0; } // 编译步骤 $ gcc -o lo_create lo_create.c -lpq // 运行结果 $ ./lo_create 连接成功 大对象创建成功,OID: 16384 写入 33 字节数据 大对象记录插入成功

3.2 大对象存储

3.2.1 导入文件到大对象

— 导入文件到大对象

— 1. 使用lo_import函数
SELECT lo_import(‘/postgresql/data/documents/report.pdf’);
— 返回:16386(OID值)

— 2. 将导入的大对象关联到表
INSERT INTO fgedu_documents (filename, file_size, file_type, file_data)
VALUES (‘report.pdf’, 1024000, ‘fgapplication/pdf’, 16386);

— 3. 批量导入文件
DO $$
DECLARE
file_oid OID;
file_path TEXT;
file_name TEXT;
BEGIN
FOR file_path, file_name IN
SELECT ‘/postgresql/data/documents/’ || filename, filename
FROM pg_ls_dir(‘/postgresql/data/documents/’) AS filename
WHERE filename LIKE ‘%.pdf’
LOOP
file_oid := lo_import(file_path);
INSERT INTO fgedu_documents (filename, file_size, file_type, file_data)
VALUES (file_name, pg_stat_file(file_path).size, ‘fgapplication/pdf’, file_oid);
END LOOP;
END $$;

3.2.2 使用libpq导入文件

// 使用libpq导入文件到大对象
// 文件:lo_import_file.c
// from:www.itpux.com.qq113257174.wx:itpux-com
// web: http://www.fgedu.net.cn

#include
#include
#include
#include
#include #include

int import_file(PGconn *conn, const char *filename, const char *filepath) {
// 获取文件大小
struct stat st;
if (stat(filepath, &st) != 0) {
fprintf(stderr, “无法获取文件信息: %s\n”, filepath);
return 0;
}

// 导入文件到大对象
Oid lobjId = lo_import(conn, filepath);
if (lobjId == 0) {
fprintf(stderr, “导入文件失败: %s\n”, PQerrorMessage(conn));
return 0;
}

// 插入记录
char query[512];
const char *file_ext = strrchr(filename, ‘.’);
const char *file_type = “fgapplication/octet-stream”;

if (file_ext != NULL) {
if (strcmp(file_ext, “.pdf”) == 0) file_type = “fgapplication/pdf”;
else if (strcmp(file_ext, “.jpg”) == 0 || strcmp(file_ext, “.jpeg”) == 0) file_type = “image/jpeg”;
else if (strcmp(file_ext, “.png”) == 0) file_type = “image/png”;
else if (strcmp(file_ext, “.txt”) == 0) file_type = “text/plain”;
}

sprintf(query, “INSERT INTO fgedu_documents (filename, file_size, file_type, file_data) VALUES (‘%s’, %ld, ‘%s’, %u)”,
filename, st.st_size, file_type, lobjId);

PGresult *res = PQexec(conn, query);
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
fprintf(stderr, “插入记录失败: %s\n”, PQerrorMessage(conn));
lo_unlink(conn, lobjId);
PQclear(res);
return 0;
}
PQclear(res);

printf(“文件导入成功: %s (OID: %u, 大小: %ld bytes)\n”, filename, lobjId, st.st_size);
return 1;
}

int main() {
const char *conninfo = “fgedu.net.cn=localfgedu.net.cn port=5432 fgedudb=fgedudb fgedu=pgsql password=postgres_password”;
PGconn *conn = PQconnectdb(conninfo);

if (PQstatus(conn) != CONNECTION_OK) {
fprintf(stderr, “连接失败: %s\n”, PQerrorMessage(conn));
PQfinish(conn);
return 1;
}

// 导入文件
import_file(conn, “report.pdf”, “/postgresql/data/documents/report.pdf”);
import_file(conn, “image.jpg”, “/postgresql/data/documents/image.jpg”);
import_file(conn, “data.txt”, “/postgresql/data/documents/data.txt”);

PQfinish(conn);
return 0;
}

// 编译步骤
$ gcc -o lo_import_file lo_import_file.c -lpq

// 运行结果
$ ./lo_import_file
文件导入成功: report.pdf (OID: 16387, 大小: 1024000 bytes)
文件导入成功: image.jpg (OID: 16388, 大小: 204800 bytes)
文件导入成功: data.txt (OID: 16389, 大小: 1024 bytes)

3.3 大对象读取

3.3.1 使用SQL读取大对象

— 使用SQL读取大对象

— 1. 导出大对象到文件
SELECT lo_export(file_data, ‘/postgresql/data/output/report.pdf’)
FROM fgedu_documents WHERE id = 1;

— 2. 获取大对象信息
SELECT
d.id,
d.filename,
d.file_size,
d.file_type,
d.file_data,
lom.lomowner,
lom.lomacl
FROM fgedu_documents d
JOIN pg_largeobject_metadata lom ON d.file_data = lom.oid
WHERE d.id = 1;

— 3. 读取大对象数据(使用lo_get函数,PostgreSQL 9.5+)
SELECT lo_get(file_data) FROM fgedu_documents WHERE id = 1;

— 4. 读取大对象的部分数据(使用lo_get函数,PostgreSQL 9.5+)
SELECT lo_get(file_data, 0, 1024) FROM fgedu_documents WHERE id = 1;

3.3.2 使用libpq读取大对象

// 使用libpq读取大对象
// 文件:lo_read.c
// from:www.itpux.com.qq113257174.wx:itpux-com
// web: http://www.fgedu.net.cn

#include
#include
#include #include

int export_large_object(PGconn *conn, Oid lobjId, const char *filename) {
// 打开大对象进行读取
int lobj_fd = lo_open(conn, lobjId, INV_READ);
if (lobj_fd < 0) { fprintf(stderr, "打开大对象失败: %s\n", PQerrorMessage(conn)); return 0; } // 创建输出文件 FILE *fp = fopen(filename, "wb"); if (fp == NULL) { fprintf(stderr, "创建文件失败: %s\n", filename); lo_close(conn, lobj_fd); return 0; } // 读取大对象数据并写入文件 char buffer[8192]; int total_read = 0; int bytes_read; while ((bytes_read = lo_read(conn, lobj_fd, buffer, sizeof(buffer))) > 0) {
fwrite(buffer, 1, bytes_read, fp);
total_read += bytes_read;
}

fclose(fp);
lo_close(conn, lobj_fd);

printf(“导出成功: %s (%d bytes)\n”, filename, total_read);
return 1;
}

int main() {
const char *conninfo = “fgedu.net.cn=localfgedu.net.cn port=5432 fgedudb=fgedudb fgedu=pgsql password=postgres_password”;
PGconn *conn = PQconnectdb(conninfo);

if (PQstatus(conn) != CONNECTION_OK) {
fprintf(stderr, “连接失败: %s\n”, PQerrorMessage(conn));
PQfinish(conn);
return 1;
}

// 查询大对象信息
PGresult *res = PQexec(conn, “SELECT id, filename, file_data FROM fgedu_documents LIMIT 3”);
if (PQresultStatus(res) != PGRES_TUPLES_OK) {
fprintf(stderr, “查询失败: %s\n”, PQerrorMessage(conn));
PQclear(res);
PQfinish(conn);
return 1;
}

int nrows = PQntuples(res);
for (int i = 0; i < nrows; i++) { int id = atoi(PQgetvalue(res, i, 0)); char *filename = PQgetvalue(res, i, 1); Oid lobjId = (Oid)atoi(PQgetvalue(res, i, 2)); char output_path[256]; sprintf(output_path, "/postgresql/data/output/%s", filename); export_large_object(conn, lobjId, output_path); } PQclear(res); PQfinish(conn); return 0; } // 编译步骤 $ gcc -o lo_read lo_read.c -lpq // 运行结果 $ ./lo_read 导出成功: /postgresql/data/output/report.pdf (1024000 bytes) 导出成功: /postgresql/data/output/image.jpg (204800 bytes) 导出成功: /postgresql/data/output/data.txt (1024 bytes)

3.4 大对象删除

3.4.1 使用SQL删除大对象

— 使用SQL删除大对象

— 1. 删除单个大对象
SELECT lo_unlink(file_data) FROM fgedu_documents WHERE id = 1;

— 2. 删除记录并自动删除大对象(使用触发器)
DELETE FROM fgedu_documents WHERE id = 1;

— 3. 批量删除大对象
DO $$
DECLARE
rec RECORD;
BEGIN
FOR rec IN SELECT file_data FROM fgedu_documents WHERE created_at < CURRENT_DATE - INTERVAL '1 year' LOOP PERFORM lo_unlink(rec.file_data); END LOOP; DELETE FROM fgedu_documents WHERE created_at < CURRENT_DATE - INTERVAL '1 year'; END $$; -- 4. 清理孤立的大对象(没有引用的大对象) DO $$ DECLARE rec RECORD; BEGIN FOR rec IN SELECT lom.oid FROM pg_largeobject_metadata lom LEFT JOIN fgedu_documents d ON lom.oid = d.file_data WHERE d.id IS NULL LOOP PERFORM lo_unlink(rec.oid); RAISE NOTICE '删除孤立大对象: %', rec.oid; END LOOP; END $$;

3.4.2 使用libpq删除大对象

// 使用libpq删除大对象
// 文件:lo_delete.c
// from:www.itpux.com.qq113257174.wx:itpux-com
// web: http://www.fgedu.net.cn

#include
#include
#include #include

int delete_large_object(PGconn *conn, int document_id) {
// 查询大对象OID
char query[256];
sprintf(query, “SELECT file_data FROM fgedu_documents WHERE id = %d”, document_id);

PGresult *res = PQexec(conn, query);
if (PQresultStatus(res) != PGRES_TUPLES_OK || PQntuples(res) == 0) {
fprintf(stderr, “查询失败或记录不存在\n”);
PQclear(res);
return 0;
}

Oid lobjId = (Oid)atoi(PQgetvalue(res, 0, 0));
PQclear(res);

// 删除大对象
if (lo_unlink(conn, lobjId) < 0) { fprintf(stderr, "删除大对象失败: %s\n", PQerrorMessage(conn)); return 0; } // 删除记录 sprintf(query, "DELETE FROM fgedu_documents WHERE id = %d", document_id); res = PQexec(conn, query); if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "删除记录失败: %s\n", PQerrorMessage(conn)); PQclear(res); return 0; } PQclear(res); printf("删除成功: 文档ID %d, 大对象OID %u\n", document_id, lobjId); return 1; } int cleanup_orphaned_lobs(PGconn *conn) { PGresult *res = PQexec(conn, "SELECT lom.oid FROM pg_largeobject_metadata lom " "LEFT JOIN fgedu_documents d ON lom.oid = d.file_data " "WHERE d.id IS NULL"); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr, "查询失败: %s\n", PQerrorMessage(conn)); PQclear(res); return 0; } int nrows = PQntuples(res); int deleted = 0; for (int i = 0; i < nrows; i++) { Oid lobjId = (Oid)atoi(PQgetvalue(res, i, 0)); if (lo_unlink(conn, lobjId) == 0) { deleted++; printf("删除孤立大对象: %u\n", lobjId); } } PQclear(res); printf("清理完成,删除 %d 个孤立大对象\n", deleted); return deleted; } int main() { const char *conninfo = "fgedu.net.cn=localfgedu.net.cn port=5432 fgedudb=fgedudb fgedu=pgsql password=postgres_password"; PGconn *conn = PQconnectdb(conninfo); if (PQstatus(conn) != CONNECTION_OK) { fprintf(stderr, "连接失败: %s\n", PQerrorMessage(conn)); PQfinish(conn); return 1; } // 删除指定文档 delete_large_object(conn, 1); // 清理孤立大对象 cleanup_orphaned_lobs(conn); PQfinish(conn); return 0; } // 编译步骤 $ gcc -o lo_delete lo_delete.c -lpq // 运行结果 $ ./lo_delete 删除成功: 文档ID 1, 大对象OID 16387 删除孤立大对象: 16390 删除孤立大对象: 16391 清理完成,删除 2 个孤立大对象

风哥提示:大对象的删除需要谨慎处理,确保在删除记录的同时删除对应的大对象,避免产生孤立的大对象占用存储空间。更多学习教程公众号风哥教程itpux_com

Part04-生产案例与实战讲解

4.1 大对象问题

在使用大对象时,可能会遇到以下问题:

4.1.1 存储问题

# 大对象存储问题

# 1. 存储空间不足
# 症状:导入大对象时失败
# 原因:磁盘空间不足
# 解决方案:
# – 清理不必要的大对象
# – 扩展存储空间
# – 归档历史数据

# 2. 大对象孤立
# 症状:存在没有引用的大对象
# 原因:删除记录时未删除大对象
# 解决方案:
# – 使用触发器自动删除
# – 定期清理孤立大对象
# – 使用外键约束(PostgreSQL 11+)

# 3. 权限问题
# 症状:无法访问大对象
# 原因:用户权限不足
# 解决方案:
# – 授予大对象权限
# – 使用SET SESSION AUTHORIZATION
# – 调整pg_largeobject权限

4.1.2 性能问题

# 大对象性能问题

# 1. 读取速度慢
# 症状:读取大对象时响应慢
# 原因:大对象数据分散存储
# 解决方案:
# – 使用流式读取
# – 增加shared_buffers
# – 使用SSD存储

# 2. 写入速度慢
# 症状:导入大对象时速度慢
# 原因:大量随机IO
# 解决方案:
# – 使用批量导入
# – 调整checkpoint参数
# – 使用异步提交

# 3. 备份恢复慢
# 症状:备份和恢复大对象时速度慢
# 原因:大对象数据量大
# 解决方案:
# – 使用pg_dump的–blobs选项
# – 使用文件系统备份
# – 归档旧数据

4.2 大对象解决方案

# 大对象解决方案

# 1. 存储优化
– 使用TOAST存储
– 定期清理孤立大对象
– 归档历史数据
– 使用压缩存储

# 2. 性能优化
– 使用流式读写
– 增加缓存大小
– 使用SSD存储
– 优化查询语句

# 3. 安全优化
– 使用权限控制
– 加密敏感数据
– 审计访问日志
– 定期备份

# 4. 管理优化
– 使用触发器自动管理
– 定期监控存储使用
– 建立数据保留策略
– 自动化运维脚本

4.3 大对象实战案例

# 案例:企业文档管理系统

# 1. 需求分析
# – 存储PDF、Word、图片等文档
# – 支持文档上传、下载、删除
# – 支持文档分类和检索
# – 支持版本控制

# 2. 数据库设计

## 文档表
CREATE TABLE fgedu_documents (
id SERIAL PRIMARY KEY,
filename VARCHAR(255) NOT NULL,
file_size BIGINT NOT NULL,
file_type VARCHAR(50) NOT NULL,
file_data OID,
category_id INTEGER REFERENCES fgedu_categories(id),
version INTEGER DEFAULT 1,
created_by INTEGER REFERENCES fgedu_fgedus(id),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

## 文档版本表
CREATE TABLE fgedu_document_versions (
id SERIAL PRIMARY KEY,
document_id INTEGER REFERENCES fgedu_documents(id),
version INTEGER NOT NULL,
file_data OID,
created_by INTEGER REFERENCES fgedu_fgedus(id),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

## 触发器:删除文档时删除大对象
CREATE OR REPLACE FUNCTION delete_document_large_object()
RETURNS TRIGGER AS $$
BEGIN
IF OLD.file_data IS NOT NULL THEN
PERFORM lo_unlink(OLD.file_data);
END IF;
RETURN OLD;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_delete_document_large_object
BEFORE DELETE ON fgedu_documents
FOR EACH ROW
EXECUTE FUNCTION delete_document_large_object();

# 3. 实施效果
# – 支持存储最大4TB的文档
# – 支持流式上传下载
# – 自动清理孤立大对象
# – 支持文档版本控制

# 4. 运维管理
# – 定期备份大对象数据
# – 监控存储使用情况
# – 归档历史版本
# – 清理过期文档

风哥教程针对风哥教程针对风哥教程针对生产环境建议:在生产环境中使用大对象时,建议建立完善的管理机制,包括自动清理、定期备份、存储监控等,确保系统的稳定性和可靠性。from PostgreSQL:www.itpux.com

Part05-风哥经验总结与分享

5.1 大对象使用技巧

大对象使用技巧:

  • 选择合适类型:小文件用BYTEA,大文件用OID
  • 使用触发器:自动管理大对象生命周期
  • 流式读写:避免一次性加载大对象
  • 定期清理:清理孤立大对象,释放空间
  • 权限控制:合理设置大对象访问权限
  • 备份策略:制定完善的大对象备份策略
  • 监控存储:监控大对象存储使用情况
  • 归档策略:归档历史数据,优化性能
风哥提示:大对象管理需要综合考虑存储、性能、安全等多个方面,建立完善的管理机制是确保系统稳定运行的关键。

5.2 大对象监控

— 大对象监控脚本

— 1. 查看大对象统计信息
SELECT
COUNT(*) as total_lobs,
SUM(pg_largeobject_metadata.len) as total_size,
AVG(pg_largeobject_metadata.len) as avg_size,
MAX(pg_largeobject_metadata.len) as max_size
FROM pg_largeobject_metadata;

— 2. 查看大对象分布
SELECT
CASE
WHEN pg_largeobject_metadata.len < 1024 THEN '< 1KB' WHEN pg_largeobject_metadata.len < 1024*1024 THEN '1KB - 1MB' WHEN pg_largeobject_metadata.len < 10*1024*1024 THEN '1MB - 10MB' WHEN pg_largeobject_metadata.len < 100*1024*1024 THEN '10MB - 100MB' ELSE '> 100MB’
END as size_range,
COUNT(*) as count,
pg_size_pretty(SUM(pg_largeobject_metadata.len)) as total_size
FROM pg_largeobject_metadata
GROUP BY 1
ORDER BY 2 DESC;

— 3. 查看孤立大对象
SELECT
COUNT(*) as orphaned_count,
pg_size_pretty(SUM(lom.len)) as orphaned_size
FROM pg_largeobject_metadata lom
LEFT JOIN fgedu_documents d ON lom.oid = d.file_data
WHERE d.id IS NULL;

— 4. 查看大对象增长趋势
SELECT
DATE_TRUNC(‘day’, lom.lomcreated) as date,
COUNT(*) as new_lobs,
pg_size_pretty(SUM(lom.len)) as new_size
FROM pg_largeobject_metadata lom
GROUP BY 1
ORDER BY 1 DESC
LIMIT 30;

5.3 资源与工具

大对象相关资源与工具:

  • PostgreSQL官方文档:https://www.postgresql.org/docs/current/largeobjects.html
  • pg_largeobject系统表:存储大对象数据
  • pg_largeobject_metadata系统表:存储大对象元数据
  • lo_*函数:大对象操作函数
  • libpq库:提供大对象编程接口
  • pgAdmin:图形化管理大对象
持续学习:大对象技术是PostgreSQL的重要特性,建议深入学习官方文档,掌握更多高级用法和最佳实践。

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

联系我们

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

微信号:itpux-com

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