通过 DB Link 分块 CLOB

问题描述 投票:0回答:1

我们已经使用了这个程序(借来的),而且效果很好。

create or replace function fn_dblink_clob(
    p_dblink    in varchar2
  , v_remote_table in varchar2
  , p_clob_col  in varchar2
  , p_rid       in urowid
)
return clob is
    /**  A function to fetch a CLOB column over a dblink  **/
    /**  Laurence Prescott 25-Aug-17  **/
    /**  select dblink_clob('some_dblink', 'some_clob_column', rowid)
           from some_table@some_dblink;
         Note: Does not work on tables that have a virtual column (eg. xmltype).
    **/

    c_chunk_size    constant pls_integer := 4000;
    v_chunk         varchar2(5000);
    v_clob          clob;
    v_pos           pls_integer := 1;
begin
    dbms_lob.createtemporary(v_clob, true, dbms_lob.call);
    loop
        execute immediate 
            'select dbms_lob.substr@' ||p_dblink|| '(' ||p_clob_col|| ', ' ||c_chunk_size
         || ', ' ||v_pos|| ') from ' ||v_remote_table|| '@' ||p_dblink|| ' where rowid = :rid '
        into v_chunk using p_rid;
        begin dbms_lob.append(v_clob, v_chunk);
        exception when others then
            if sqlcode = -6502 then exit; else raise; end if;
        end;
        if length(v_chunk) < c_chunk_size then exit; end if;
        v_pos := v_pos + c_chunk_size;
    end loop;
    return v_clob;
end fn_dblink_clob;

我们通常将其指向一个物理表,但现在需要指向一个 VIEW。

我可以有效地执行代码并运行此语句以通过 DB Link 返回 CLOB,它工作正常。

select dbms_lob.substr@ARGUS_TRANSCT_DB(NARRATIVE, 4000,1) from ARGUS_CUSTOM.dlp_case_narrative_rowid@ARGUS_TRANSCT_DB where row_id = 'AAATVIAIpAAABzOAAD'

当我尝试将函数作为 SQL 语句的一部分运行时:

  select 
    ROW_ID, 
    CASE_ID, 
    fn_dblink_clob('ARGUS_TRANSCT_DB', 'ARGUS_CUSTOM.dlp_case_narrative_rowid','NARRATIVE', NARR.ROW_ID) as NARRATIVE
  
 from ARGUS_CUSTOM.dlp_case_narrative_rowid@ARGUS_TRANSCT_DB NARR

我明白了:

ORA-01446: cannot select ROWID from, or sample, a view with DISTINCT, GROUP BY, etc.
ORA-02063: preceding line from ARGUS_TRANSCT_DB
ORA-06512: at "PV_COMPLIANCE.FN_DBLINK_CLOB", line 22
01446. 00000 -  "cannot select ROWID from, or sample, a view with DISTINCT, GROUP BY, etc."
*Cause:    
*Action:

所以视图中没有 distinct 或 group by 子句。这个函数动态地做的是建立我知道针对这个视图执行的语句。

远程机器上的基本视图定义,没有连接,没有分组依据或不同的子句。

CREATE VIEW DLP_CASE_NARRATIVE_ROWID
    AS 
SELECT ROWID AS "ROW_ID", "CASE_ID",
"ABBREV_NARRATIVE",
"DELETED",
"NARRATIVE",
"ABBREV_NARRATIVE_J",
"NARRATIVE_J",
"DLP_REVISION_NUMBER",
"EFFECTIVE_START_DATE",
"EFFECTIVE_END_DATE",
"DELETED_FLAG",
"ENTERPRISE_ID" FROM DLP_OWNER.DLP_CASE_NARRATIVE
oracle clob dblink
1个回答
0
投票

我看到您有一个 ROWID(别名为 row_id)在您的视图中显式公开。只需使用那个...查询 row_id 而不是 rowid.

execute immediate 
            'select dbms_lob.substr@' ||p_dblink|| '(' ||p_clob_col|| ', ' ||c_chunk_size
         || ', ' ||v_pos|| ') from ' ||v_remote_table|| '@' ||p_dblink|| ' where row_id = :rid '
        into v_chunk using p_rid;

仅供参考,我做了与您正在做的相同的事情 - 创建一个过程,该过程将 LOB 分块以便通过 dblink 进行更快的处理。不过,我的做法有所不同,我将过程放在远程数据库上,然后传入一组 ROWID。该过程将 CLOB 读入本地集合,将它们转换为 BLOB,压缩它们,然后将它们分块成 RAW 集合,将该集合作为 OUT 参数返回给调用者,调用者是本地数据库上的一个过程。该过程反转了该过程,从 RAW 集合中重新组装 BLOB,解压缩,转换为 CLOB,然后使用 CLOB 值更新目标表。出于与您遇到的相同原因,我也不支持从复杂视图中提取,因为我的代码需要来自源的 ROWID。但解决方案是重写视图,使其在顶层只有一个表,所有其他连接都由子查询完成。

我还有一个首次通过机制,可以将任何小于该大小的 CLOB 拉为 VARCHAR2(4000)(通过 CAST)。这比将它们作为 CLOB 提取要快得多。但这仍然需要 ROWID.

我还应该指出,虽然这在 10 多年前让我在 10g-11g 时代的 Oracle 本机 LOB-over-dblink 上获得了相当大的性能提升,但在最近的版本中,我发现他们已经调整了内部处理和本机LOB 传输现在快得多,因此可能不再值得使用这种 hacky 解决方法。

© www.soinside.com 2019 - 2024. All rights reserved.