暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PostgreSQL特性矩阵解析系列1之large objects

571

前言

PG中的large objects有区别于Oracle中的clob、blob这些类型。


large object操作

  1. 创建large object

    select pg_catalog.lo_create('521');#创建了一个oid为0521的large object。
    test=# select * fr
    om pg_largeobjec | lomowner t_metadata; #查询large object元数据表。
    oid | lomowner | lomacl
    -----+----------+--------
    521 | 10 |

    2.打开large object并写入数据

      test=# begin;
      BEGIN
      test=# 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;
      COMMIT




      test=# select * from pg_largeobject;
      loid | pageno | data

      ------+--------+----------------------------------------------------------------------------------------------------------------------
      ----------------------------------------
      521 | 0 | \x5c78303030303031303030313030313031303130303030303030303030303238303130303030313630303030303032383030303030303130303
      030303030323030303030303030313030303430
      (1 row)

      3.将large object存储进表(说与表关联更合适^_^)

        test=# create table lo_test(lo oid);#存储为oid
        CREATE TABLE
        test=# insert into lo_test(lo) values(521);
        INSERT 0 1
        test=# 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的relfilenode
          RowExclusiveLock);



          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

            文章转载自CP的PostgreSQL厨房,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

            评论