1、初识postgresql large object

一位同事在对使用pg_dump备份出来的文件(使用plain格式)进行恢复时,觉得速度非常慢,让我分析一下是什么原因。

我拿到他的.bak文件,文件有1个多G。为了方便分析,我用split工具把文件给拆成了多个小文件。在.bak文件中,我发现有大量这样的SQL:

通过查询文档,我知道lo表示large object。还别说,这是我第一次接触到postgresql 中的large object 。因为受oracle中LOB概念的影响,我想当然地以为large object 也是postgresql中的一种数据类型,就像ORACLE中的BLOB或CLOB。可是翻看了参考书籍与官方文档后,发现竟然没有对应的字段类型。网上有人说,postgresql中的large object,其对应的字段类型为oid。这样的说法让我真的好费解,只到最后,待我搞明白large object是怎么回事后,我意识到这样说的人大概知道一点,但应该没有理解透。

在查询官方文档的过程中,接触到两张与large object相关的系统表:

简单点说,pg_largeobject_metadata表是large object的元数据表,记录每个large object的OID(对象标识符)、属主、访问权限。Pg_largeobject表是具体存储large object的表,其存储方式为:将large ojbect以page(2K)为单位分成多个单元,第个单元在Pg_largeobject中表示为1条记录。

可是,我没有发现有任何说明,可以解释如何以large object作为字段值。

2、如何理解postgresql large object

在oracle中,假设我们定义了表的一个字段类型为BLOB,例如

Create table t (desc blob)

然后我们可以向该字段中插入记录: insert into t values ('0Xadfe4358942c')

最后,在我们查询时,直接select desc from t 就会返回:

0Xadfe4358942c

我错就错在默认了postgresql也是这么玩儿的。然而呢?

实际上,在postgresql中(至少截止到9.6版本)没有large object字段。Large object在postgresql中是作为一个个的对象存在的,可以使用特定方法以oid来引用它们。我们来举个现实中的例子来说明一下:假如把数据库表的每条记录比喻成1个人,LOB比喻成1只狗,那么oracle的处理方式为1个人有了1只狗,数据库中才有了这只狗。而关于这只狗怎么来的,是凭空变出来的、基因克隆的、还是自己用泥巴做的,oracle不管它。postgresql large object的管理方式则不同,数据库中首先得有1只狗或多只狗,然后这个人就可以办理领养手续,但领养手续只完成领养登记,表示这只狗属于你了,但狗你不能真正带回家。因为狗并没有真正带回来,所以多个人可以登记领养同一只狗,只需要将领养编号赋予同一只狗的ID即可。

3、Postgresql large object 的使用

上面只是一个比喻,那postgresql large object如何使用的呢?使用过程中的每一步操作又对应上文的什么内容呢?

我们就以.bak中的过程来做示例。

  1. 创建large object (数据库中有了一只狗,但现在这只狗还只是个概念,还不是实体)

    执行该过程后,会在pg_largeobject_metadata中生成1条记录,oid字段值为1000001。而pg_largeobject表不会生成相应记录,因为现在的large object还是空的。

  2. 打开large object (找到这只狗,准备为它赋予生命)--执行这一步前需要开启事务: begin;

  3. 为large object 注入实际数据 (给狗赋予生命,让它变成一个实体)--执行这一步后需要提交事务:commit;

    执行该过程后,会在pg_largeobject生成记录,记录的条数与large object的大小有关(每2K大小一条记录)

  4. 至此,狗已经有了,但它只是孤零零地在那时。现在需要有人对它办理领养登记

    我们新建一张表:

    然后往该表中插入一条记录,lo字段的值为1000001

    好了,我们现在领养手续办理完了。可能有人要说,不对呀,这就完了?是的,这就完了。从这里可以看出,人知道它领养了哪只狗,但狗不知道谁领养了它。在计算机术语来说,就是引用者知道被引用者,但被引用者不知道引用者。

    现在领也领养了,但有什么意义呢?就这么标识一下引用,是不是就可以通过test表的lo字段来查看large object的内容呢?我们来看一下:

    很遗憾,看到的只是引用值,看不到large object的具体的值。实际上,在postgresql中,对large object 的使用需要使用专门的方法,不能直接使用引用字段的方式来查看、使用。

  5. 办理领养登记之后的使用

    办理领养登记之后,可以的方法包括:

    1. lo_export(oid loid, text filename) --将大对象loid的数据导出到一个服务器文件filename中,返回导出长度(整型)。
    2. lo_unlink(oid loid)      -- 删除一个地址为loid的大对象,返回整型 1-成功  -1 -失败。
    3. lo_open(oid loid, integer open_mode)  -- 打开一个地址为loid的大对象,为读写做准备,open_mode为打开类型: inv_write(写,值为131072)、inv_read(读,值为262144)或者inv_write|inv_read (读写,值为393216)。返回文件句柄fd(整型),若fd为负数,失败。
    4. loread(integer fd, integer len)  -- 读句柄fd当前位置开始的len大小的数据,返回数据内容(bytea类型)。
    5. lowrite(integer fd, bytea buf)   -- 在句柄fd当前位置开始将二进制数据buf写入大对象中,返回所写的长度(整型)。
    6. lo_lseek(integer fd, integer offset, integer whence) -- 改变句柄fd当前的读写位置。whence是寻址方式,seek_set(值为0)从对象头开始,seek_cur(值为1)从当前读写位置开始,seek_end(值为2)从对象尾开始,offset是偏移尺寸。返回新的读写位置(整型),-1表示错误。

      注:loread、lowrite会自动改变当前读写位置,所以若顺序读写,lo_lseek这个命令就没什么用。

    7. lo_tell(integer fd)      -- 返回句柄fd的当前位置(整型)
    8. lo_truncate(integer fd, integer len) -- 截取句柄fd所打开的大对象长度为len大小。若len大于原来大对象的长度,会在大对象后缀一个'\0'字符。成功返回0,失败为负数。
    9. lo_close(integer fd)    -- 关闭句柄fd, 成功返回0,失败为负数。

      以上函数涉及到df句柄的,必须在一个transaction内完成,也就是说句柄fd只在一个事务内有效,事务结束它自动关闭。

  6. 使用案例

例如,我们可以lo_export方法将test表lo字段所对应的large object导出到本地。

查看test.f文件

通过查询1f 8b 08文件头所对应的文件格式,可知test.f文件为gz压缩文件。通过gunzip解压test.f文件

好,现在我们看清它的明文是什么了。这实际是一种矢量瓦片的明码格式。

Postgresql中的large object的更多相关文章

  1. Large Object Heap内存碎片在.NET 4.5中的改进

    .NET 4.5已然到来,预览了解了下Large Object Heap在.NET 4.5中的效能改进.借此和大家来探讨下.本文不讨论Loder Heap,SOH(samll object heap) ...

  2. 关于LOH(Large Object Heap)及内存泄漏

    关于LOH(Large Object Heap)的. .NET CLR中对于大于85000字节的内存既不像引用类型那样分配到普通堆上,也不像值类型那样分配到栈上,而是分配到了一个特殊的称为LOH的内部 ...

  3. BLOB (binary large object)

    BLOB (binary large object),二进制大对象,是一个可以存储二进制文件的容器. 在计算机中,BLOB常常是数据库中用来存储二进制文件的字段类型. BLOB是一个大文件,典型的BL ...

  4. 通过arcgis在PostgreSQL中创建企业级地理数据库

    部署环境: Win7 64位旗舰版 软件版本: PostgreSQL-9.1.3-2-windows-x64 Postgis-pg91x64-setup-2.0.6-1 Arcgis 10.1 SP1 ...

  5. 【前端】js中new和Object.create()的区别

    js中new和Object.create()的区别 var Parent = function (id) { this.id = id this.classname = 'Parent' } Pare ...

  6. buffer cache中,各个object对象占用的buffer blocks

    buffer cache中,各个object对象占用的buffer blocks: COLUMN OBJECT_NAME FORMAT A40 COLUMN NUMBER_OF_BLOCKS FORM ...

  7. PostgreSQL 中日期类型转换与变量使用及相关问题

    PostgreSQL中日期类型与字符串类型的转换方法 示例如下: postgres=# select current_date; date ------------ 2015-08-31 (1 row ...

  8. PostgreSQL 中定义自己需要的数据类型

    PostgreSQL解决某系数据库中的tinyint数据类型问题,创建自己需要的数据类型如下: CREATE DOMAIN tinyint AS smallint CONSTRAINT tinyint ...

  9. 在PostgreSQL中使用oracle_fdw访问Oracle

    本文讲述如何在PostgreSQL中使用oracle_fdw访问Oracle上的数据. 1. 安装oracle_fdw 可以参照:oracle_fdw in github 编译安装oracle_fdw ...

随机推荐

  1. CSS——设置边框渐变色

    前言 最近在写一个typecho的主题,刚好遇到这样一个问题就记录下吧 步骤 这是一个CSS的过度效果,效果如下. 代码 .object{ width: 50px; height: 50px; bac ...

  2. ActiveMQ-启动服务异常

    如果报这种异常: Caused by: java.io.IOException: Failed to bind to server socket: tcp://0.0.0.0:61616?maximu ...

  3. tensorflow API _ 5 (tensorflow.summary)

    tensorflow的可视化是使用summary和tensorboard合作完成的. 基本用法 首先明确一点,summary也是op. 输出网络结构 with tf.Session() as sess ...

  4. LeetCode 1239. Maximum Length of a Concatenated String with Unique Characters

    原题链接在这里:https://leetcode.com/problems/maximum-length-of-a-concatenated-string-with-unique-characters ...

  5. 洛谷 P2746 [USACO5.3]校园网 Network of Schools 题解

    Tarjan 模板题 第一问就是缩点之后看有多少个入度为零的点就好了. 第二问是在缩点后将每个点的入度和出度都求出(只要有入度或出度就置为1),然后比较哪个有值的多,将多的作为答案输出.原因是由题可得 ...

  6. learning java Charset 查看支持的字符集类型

    import java.nio.charset.Charset; import java.util.SortedMap; public class CharsetTest { public stati ...

  7. let

    let a=2+2 #+ - * / % ** 都支持 支持类C的计算方式 let i++ let i-- let i+=10 let i-=10 let i*=10 let i/=10 let i% ...

  8. MySQL limit 分页查询优化(百万级优化)

    1)简单的查询分页:分每页5条 limit [offset],[rows] ,10; 2)建立id索引:查询索引id ,) limit ; 3)使用 between and 语句分页效率快N倍 ; 4 ...

  9. 产品生命周期(Product Life Circle,PLC)

    什么是产品生命周期? 产品生命周期是新产品从开发进入市场到被市场淘汰的整个过程.产品生命周期可分为初创期.成长期.成熟期.衰退期. 产品生命周期有什么用? 在产品不同的生命阶段,公司的业务目的都不同. ...

  10. Calibre中使用DeDRM插件进行Kindle电子书解锁

    小书匠 废话不多说,下面是Calibre和DeDRM插件的下载地址: https://calibre-ebook.com/download https://github.com/apprenticeh ...