如果您不太可能在一个字段中存储超过 1GB 的二进制数据,那么您最好使用普通的 bytea 类型而不是 LOB 化它。
它们不会使表膨胀,因为 PostgreSQL 会将较大的字节流存储在表外部(就像大型对象存储一样,只是透明地进行)——包括在有帮助的情况下压缩它们——同时保留所有二进制字符串函数和运算符。
(PHP 5 >= 5.1.2, PHP 7, PHP 8, PECL pdo_pgsql >= 1.0.2)
PDO::pgsqlLOBCreate — 创建新的大型对象
PDO::pgsqlLOBCreate() 创建一个大型对象并返回该对象的 OID。然后,您可以使用 PDO::pgsqlLOBOpen() 在该对象上打开一个流,以读取或写入数据。OID 可以存储在类型为 OID 的列中,并用于引用大型对象,而不会导致行的大小任意增长。大型对象将继续存在于数据库中,直到通过调用 PDO::pgsqlLOBUnlink() 删除它。
大型对象的大小可以达到 2GB,但使用起来很麻烦;您需要确保在从数据库中删除引用其 OID 的最后一行之前调用 PDO::pgsqlLOBUnlink()。此外,大型对象没有访问控制。作为替代方案,请尝试使用 bytea 列类型;最新的 PostgreSQL 版本允许 bytea 列的大小达到 1GB,并透明地管理存储以优化行大小。
注意: 此函数必须在事务中调用。
PDO::pgsqlLOBCreate() 不接受任何参数。
成功时返回新创建的大型对象的 OID,失败时返回 false
。
范例 #1 PDO::pgsqlLOBCreate() 范例
此示例创建一个新的大型对象,并将文件的內容复制到其中。然后,OID 被存储到表中。
<?php
$db = new PDO('pgsql:dbname=test host=localhost', $user, $pass);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->beginTransaction();
$oid = $db->pgsqlLOBCreate();
$stream = $db->pgsqlLOBOpen($oid, 'w');
$local = fopen($filename, 'rb');
stream_copy_to_stream($local, $stream);
$local = null;
$stream = null;
$stmt = $db->prepare("INSERT INTO BLOBS (ident, oid) VALUES (?, ?)");
$stmt->execute(array($some_id, $oid));
$db->commit();
?>
如果您不太可能在一个字段中存储超过 1GB 的二进制数据,那么您最好使用普通的 bytea 类型而不是 LOB 化它。
它们不会使表膨胀,因为 PostgreSQL 会将较大的字节流存储在表外部(就像大型对象存储一样,只是透明地进行)——包括在有帮助的情况下压缩它们——同时保留所有二进制字符串函数和运算符。
恕我直言,这里有一种比建议更好的处理 lob 对象删除的方法。程序员很容易忘记取消链接 lob。使用以下触发器,不需要程序员执行任何操作。
顺便说一句,bytea 字段的一个问题是,当您查询数据库时,如果您请求该字段,实际上会检索数据。当您查询 oid 时,只会检索 oid,然后您可以在需要时随时打开 lob。
CREATE OR REPLACE FUNCTION oidtable_after_update_delete()
RETURNS "trigger" AS
$BODY$
BEGIN
IF (TG_OP = 'UPDATE') THEN
IF (OLD.oidfield = NEW.oidfield) OR (OLD.oidfield IS NULL) THEN
RETURN NEW;
END IF;
END IF;
IF (EXISTS (SELECT 1 FROM pg_largeobject WHERE loid = OLD.oidfield)) THEN
PERFORM LO_UNLINK (OLD.oidfield);
END IF;
RETURN NEW;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;
CREATE TRIGGER oidtable_after_update_delete
AFTER UPDATE OR DELETE
ON oidtable
FOR EACH ROW
EXECUTE PROCEDURE oidtable_after_update_delete();