首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 操作 Oracle LOB:BLOB/CLOB 讀寫與效能優化完整指南

     編輯:PHP 綜合知識

Oracle LOB (Large Object) 包含 BLOB (二進位)、CLOB (字元)、NCLOB (國家字元集) 與 BFILE (外部檔案)。PHP OCI8 擴展提供完整 LOB API,本文詳細說明建立、讀取、寫入、暫時 LOB、流式處理與效能優化。

LOB 型別對照

型別資料類型最大容量典型用途OCI8 常數
BLOB二進位4GB - 1圖片、影音、加密檔、壓縮包OCI_B_BLOB
CLOB單位元組字元4GB - 1長文本、XML、JSON、日誌OCI_B_CLOB
NCLOB多位元組字元 (Unicode)4GB - 1多語言長文本OCI_B_NCLOB (PHP 8.1+)
BFILE外部檔案參考OS 限制唯讀大檔、CDN 來源OCI_B_FILE

核心操作流程

  1. oci_new_descriptor($conn, OCI_D_LOB) 建立 LOB 描述符
  2. oci_bind_by_name($stid, ':lob', $lob, -1, OCI_B_BLOB|OCI_B_CLOB) 綁定
  3. 執行 SQL (INSERT ... RETURNING lob_col INTO :lob 或 SELECT lob_col ...)
  4. 使用 LOB 方法:writeTemporary(), load(), read(), write(), save(), free()
  5. 交易提交/回滾

完整範例:寫入 BLOB (圖片)

<?php
$conn = oci_connect('user', 'pass', '//host:1521/service', 'AL32UTF8');
$imagePath = 'photo.jpg';
$imageData = file_get_contents($imagePath);

$stid = oci_parse($conn, 'INSERT INTO images (id, mime, data) VALUES (seq.nextval, :mime, :blob) RETURNING data INTO :blob');
$mime = 'image/jpeg';
$blob = oci_new_descriptor($conn, OCI_D_LOB);

oci_bind_by_name($stid, ':mime', $mime);
oci_bind_by_name($stid, ':blob', $blob, -1, OCI_B_BLOB);

// 寫入暫時 LOB
$blob->writeTemporary($imageData, OCI_TEMP_BLOB);

$r = oci_execute($stid, OCI_NO_AUTO_COMMIT);
if ($r) {
    oci_commit($conn);
    echo "上傳成功\n";
} else {
    $e = oci_error($stid); trigger_error($e['message'], E_USER_ERROR);
}
$blob->free();
oci_free_statement($stid);
oci_close($conn);

完整範例:讀取 CLOB (長文本)

<?php
$conn = oci_connect('user', 'pass', '//host:1521/service', 'AL32UTF8');
$stid = oci_parse($conn, 'SELECT content FROM articles WHERE id = :id');
$id = 123;
oci_bind_by_name($stid, ':id', $id);
oci_execute($stid);

$row = oci_fetch_assoc($stid);
if ($row) {
    $clob = $row['CONTENT']; // 自動為 LOB 描述符
    $clob->load(); // 將資料從資料庫載入描述符
    $content = $clob->read($clob->size()); // 一次性讀取 (小檔案)
    $clob->free();
    echo $content;
}
oci_free_statement($stid);
oci_close($conn);

大型 LOB 流式處理 (避免記憶體耗盡)


// 讀取大型 BLOB/CLOB 分塊輸出 (如檔案下載)
$clob->load();
$chunkSize = 8192;
while (!$clob->eof()) {
    echo $clob->read($chunkSize);
    ob_flush(); flush(); // 輸出到瀏覽器
}
$clob->free();

// 寫入大型 LOB 分塊
$blob = oci_new_descriptor($conn, OCI_D_LOB);
$stid = oci_parse($conn, 'INSERT INTO files (data) VALUES (:blob) RETURNING data INTO :blob');
oci_bind_by_name($stid, ':blob', $blob, -1, OCI_B_BLOB);
$blob->writeTemporary('', OCI_TEMP_BLOB); // 初始化空暫時 LOB

$handle = fopen('large_video.mp4', 'rb');
while (!feof($handle)) {
    $chunk = fread($handle, 8192);
    $blob->write($chunk); // 追加寫入
}
fclose($handle);

oci_execute($stid, OCI_NO_AUTO_COMMIT);
oci_commit($conn);
$blob->free();

效能優化關鍵點

策略實作效益
SecureFile LOB (Oracle 11g+)建表指定 STORE AS SECUREFILE壓縮、去重、快取、加密、更好並發
LOB 快取CACHE / NOCACHE / CACHE READS 屬性頻繁讀取啟用 CACHE
啟用壓縮COMPRESS HIGH/MEDIUM/LOW文字型 LOB 壓縮率 60-80%
去重DEDUPLICATE相同內容共享儲存
分塊大小CHUNK 8K/16K/32K (預設 8K)匹配應用讀寫模式
避免 SELECT *明確列出欄位,不要包含 LOB 欄位除非必要減少網路傳輸、記憶體
使用暫時 LOBOCI_TEMP_BLOB/CLOB 處理中介資料不產生 UNDO/REDO,速度快

常見錯誤與解決

  • ORA-22275: invalid LOB locator → LOB 描述符已 free() 或交易已提交失效,重新查詢取得
  • ORA-01555: snapshot too old → 長交易中 LOB 讀取,增加 UNDO 保留時間或縮短交易
  • 中文亂碼 → 連接指定 AL32UTF8,CLOB 存儲為 UTF-8,PHP 內部 UTF-8
  • 記憶體耗盡 → 大 LOB 必須流式處理,不要一次 read($lob->size())
  • OCI_Lob::save(): ORA-22920 → 嘗試對非暫時 LOB 直接 write(),需先 writeTemporary() 或 load()

BFILE 操作 (唯讀外部檔案)


// 建立目錄物件 (DBA 執行)
// CREATE DIRECTORY media_dir AS '/data/media';
// GRANT READ ON DIRECTORY media_dir TO php_user;

$stid = oci_parse($conn, 'SELECT bfile_col FROM documents WHERE id = :id');
oci_bind_by_name($stid, ':id', $id);
oci_execute($stid);
$row = oci_fetch_assoc($stid);
$bfile = $row['BFILE_COL'];
$bfile->open(OCI_FILE_READONLY);
while (!$bfile->eof()) {
    echo $bfile->read(8192);
}
$bfile->close();
$bfile->free();

掌握 LOB 操作是 PHP 開發企業級 Oracle 應用的核心技能,善用 SecureFile、流式處理與暫時 LOB 可大幅提升效能與穩定性。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved