前言
PG中的large objects有区别于Oracle中的clob、blob这些类型。
large object操作
创建large object
select pg_catalog.lo_create('521');#创建了一个oid为0521的large object。test=# select * from pg_largeobjec | lomowner t_metadata; #查询large object元数据表。oid | lomowner | lomacl-----+----------+--------521 | 10 |
2.打开large object并写入数据
test=# begin;BEGINtest=# select pg_catalog.lo_open('521',131072);lo_open---------0(1 row)test=# select pg_catalog.lowrite(0, '\\x000001000100101010000000000028010000160000002800000010000000200000000100040');lowrite---------77(1 row)test=# select pg_catalog.lo_close(0);lo_close----------0(1 row)test=# commit;COMMITtest=# select * from pg_largeobject;loid | pageno | data------+--------+--------------------------------------------------------------------------------------------------------------------------------------------------------------521 | 0 | \x5c78303030303031303030313030313031303130303030303030303030303238303130303030313630303030303032383030303030303130303030303030323030303030303030313030303430(1 row)
3.将large object存储进表(说与表关联更合适^_^)
test=# create table lo_test(lo oid);#存储为oidCREATE TABLEtest=# insert into lo_test(lo) values(521);INSERT 0 1test=# select * from lo_test;lo-----521
large object 源码解析
源码文件
src/backend/catalog/pg_largeobject.c
src/backend/catalog/pg_largeobject_d.h
src/include/catalog/pg_largeobject_metadata.h
src/backend/catalog/pg_largeobject_metadata_d.h
系统表
pg_largeobject
pg_largeobject_metadata
pg_largeobject系统表
pg_largeobject保存构成“大对象”的数据。一个大对象在被创建时会被分配一个OID。每个大对象被分解成段或“页”,以便小到可以被方便地作为行存储在pg_largeobject中。每页中的数据量被定义为LOBLKSIZE。
pg_largeobject的列
loid 包含此页的大对象的标识符。
pageno 此页在它所属大对象中的页号(从0开始计)。
data 实际存储在大对象中的数据。它从不会超过LOBLKSIZE字节。
pg_largeobject_metadata系统表
pg_largeobject_metadata保持着与大对象有关的元数据。真正的大对象数据被存储在pg_largeobject中。
pg_largeobject_metadata的列
oid 行标识符
lomowner 大对象的拥有者
lomacl 访问权限
"大对象处理"
src/backend/catalog/pg_largeobject.c/** 创建一个具有给定 LO 标识符的大对象.** 通过在pg_largeobject_metadata中插入一个条目(不含任何数据页)来创建一个新的大对象,这样该对象的大小就会显示为0。*/Oid LargeObjectCreate(Oid loid){Relation pg_lo_meta;Relation pg_largeobject;ScanKeyData skey[1];SysScanDesc scan;HeapTuple tuple;pg_lo_meta = table_open(LargeObjectMetadataRelationId, # RelationId=2995 此值为固定值,该值也为 pg_largeobject_metadata的relfilenodeRowExclusiveLock);pg_largeobject = table_open(LargeObjectRelationId,RowExclusiveLock);... ... ...}/**删除具有给定LO标识符的大对象。数据页和元数据都必须删除。*/void LargeObjectDrop(Oid loid){...}/** 对于大对象元数据,我们不使用系统缓存,因为害怕使用过多的本地内存。* 此函数始终使用最新快照扫描系统目录,因此在以只读模式打开大对象时不应使用它(因为以只读模式打开的大对象应该相对于 *调用者的快照,而在读写模式下它们是相对于当前快照的。*/bool LargeObjectExists(Oid loid){...}src/backend/catalog/pg_largeobject.h/* ----------------* CPP将此转换为typedef struct formdata pg largeObject* ----------------*/CATALOG(pg_largeobject,2613,LargeObjectRelationId) #2163该值也为 pg_largeobject的relfilenode{Oid loid; /* Identifier of large object */int32 pageno; /* Page number (starting from 0) *//* data has variable length, but we allow direct access; see inv_api.c */bytea data BKI_FORCE_NOT_NULL; /* Data for page (may be* zero-length) */} FormData_pg_largeobject;
"大对象元数据处理"
src/backend/catalog/pg_largeobject_metadata.h/* ----------------*cpp将此转换为typedef struct FormData_pg_largeobject_metadata* ----------------*/CATALOG(pg_largeobject_metadata,2995,LargeObjectMetadataRelationId){Oid oid; /* oid */Oid lomowner; /* OID of the largeobject owner */#ifdef CATALOG_VARLEN /* variable-length fields start here */aclitem lomacl[1]; /* access permissions */#endif} FormData_pg_largeobject_metadata;/* ----------------* Form_pg_largeobject_metadata对应一个指向pg_largeobject_metadata关系格式的元组的指针。* ----------------*/typedef FormData_pg_largeobject_metadata *Form_pg_largeobject_metadata;nclude/catalog/pg_largeobject_metadata.h
总结
大对象全部拆成LOBLKSIZE大小,存入pg_largeobject,通过 loid进行区分, 每个大对象拆分成的各个部分通过 pageno进行顺序的关联起来。
pg的大对象,并不适合大数据量的使用,可能会影响性能。
参考
http://www.postgres.cn/docs/12/catalog-pg-largeobject.html




