【问题标题】:Get size of large object in PostgreSQL query?在 PostgreSQL 查询中获取大对象的大小?
【发布时间】:2012-04-27 11:58:04
【问题描述】:

我想获取一个 blob 的字节大小。

我正在使用 Postgresql,并希望使用 SQL 查询来获取大小。像这样的:

SELECT sizeof(field) FROM table;

这在 Postgresql 中可行吗?

更新:我已阅读 postgresql 手册,但找不到合适的函数来计算文件大小。此外,blob 被存储为一个大对象。

【问题讨论】:

  • 在发这样的问题之前请先阅读手册:postgresql.org/docs/current/static/functions.html
  • @DanielVérité:看起来确实是个骗子,但公平地说,我在发布答案之前进行搜索时找不到该问题。老实说,谁称它们为“lobjects”? ;-) 我的功能与该问题中的您的功能非常相似,但在我的辩护中,如果我复制了它,我也会复制错误处理!

标签: sql postgresql blob


【解决方案1】:

不是我用过大对象,而是看文档:http://www.postgresql.org/docs/current/interactive/lo-interfaces.html#LO-TELL

我认为您必须使用与某些文件系统 API 所需的相同技术:寻找到最后,然后告诉位置。 PostgreSQL 具有似乎包装内部 C 函数的 SQL 函数。我找不到太多文档,但这很有效:

CREATE OR REPLACE FUNCTION get_lo_size(oid) RETURNS bigint
VOLATILE STRICT
LANGUAGE 'plpgsql'
AS $$
DECLARE
    fd integer;
    sz bigint;
BEGIN
    -- Open the LO; N.B. it needs to be in a transaction otherwise it will close immediately.
    -- Luckily a function invocation makes its own transaction if necessary.
    -- The mode x'40000'::int corresponds to the PostgreSQL LO mode INV_READ = 0x40000.
    fd := lo_open($1, x'40000'::int);
    -- Seek to the end.  2 = SEEK_END.
    PERFORM lo_lseek(fd, 0, 2);
    -- Fetch the current file position; since we're at the end, this is the size.
    sz := lo_tell(fd);
    -- Remember to close it, since the function may be called as part of a larger transaction.
    PERFORM lo_close(fd);
    -- Return the size.
    RETURN sz;
END;
$$; 

测试它:

-- Make a new LO, returns an OID e.g. 1234567
SELECT lo_create(0);

-- Populate it with data somehow
...

-- Get the length.
SELECT get_lo_size(1234567);

看起来 LO 功能主要是通过客户端或通过低级服务器编程来使用的,但至少他们已经为它提供了一些 SQL 可见的函数,这使得上述操作成为可能。我查询了SELECT relname FROM pg_proc where relname LIKE 'lo%' 让自己开始。剩下的需要对 C 编程的模糊记忆和对模式 x'40000'::intSEEK_END = 2 值的一些研究!

【讨论】:

  • 为避免“结果超出范围”错误并使其适用于大于 2GB 的大型对象,请使用 lo_seek64lo_tell64
  • 性能与其他答案相比如何?
【解决方案2】:

您可以在创建大对象时更改应用程序以存储大小。否则,您可以使用如下查询:

select sum(length(lo.data)) from pg_largeobject lo
where lo.loid=XXXXXX

您也可以使用大对象 API 函数,如上一篇文章中所建议的,它们工作正常,但比上面建议的 select 方法慢一个数量级。

【讨论】:

【解决方案3】:
select pg_column_size(lo_get(lo_oid)) from table;

以字节为单位提供大小。

如果你想要漂亮的打印:

select pg_size_pretty(pg_column_size(lo_get(lo_oid))::numeric) from table;

【讨论】:

  • 不知何故总是比实际多 4 个字节,为什么?
  • @wutzebaer bytea 列的前四个字节是其余部分的大小
  • 即你应该使用octet_length(根据其他答案)而不是pg_column_size
【解决方案4】:

试试length()octet_length()

【讨论】:

    【解决方案5】:

    这是我的解决方案:

    select
    lo.loid,
    pg_size_pretty(sum(octet_length(lo.data)))
    from pg_largeobject lo
    where lo.loid in (select pg_largeobject.loid from pg_largeobject)
    group by lo.loid;
    

    【讨论】:

      【解决方案6】:

      如果 blob 列的类型是oid

      SELECT length(lo_get(blob_column)) FROM table;
      

      lo_get ( loid oid [, offset bigint, length integer ] ) → bytea

      提取大对象的内容,或其子字符串。

      ——https://www.postgresql.org/docs/current/lo-funcs.html

      长度 ( bytea ) → 整数

      返回二进制字符串中的字节数。

      ——https://www.postgresql.org/docs/current/functions-binarystring.html

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-01-03
        • 1970-01-01
        • 1970-01-01
        • 2011-10-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多