oracle 通过DB链接分块CLOB

8i9zcol2  于 2023-04-20  发布在  Oracle
关注(0)|答案(1)|浏览(173)

我们已经使用了这个程序(借用),它已经工作得很好。

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链接返回一个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子句,函数动态地构建语句,我知道,对这个视图执行很好。
远程计算机上的基本视图定义,没有联接、group by或distinct子句。

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
0s7z1bwu

0s7z1bwu1#

我看到你有一个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分块的过程,以便在dblinks上进行更快的处理。但我的做法不同,我将该过程放在远程数据库上,并传入ROWID的集合。该过程将CLOB读取到本地集合中,将其转换为BLOB,压缩它们,然后将其分块到RAW的集合中,将该集合作为OUT参数返回给调用方,该调用方是本地数据库上的过程。该过程与此过程相反,从RAW集合中重新组装BLOB,解压缩,转换为CLOB,然后使用CLOB值更新目标表。出于与您遇到的相同的原因,我也不支持从复杂的视图中拉取数据,因为我的代码需要源代码中的ROWID。但解决方案是重写视图,使其在顶层只有一个表,所有其他连接都通过子查询完成。
我还有一个第一遍机制,它可以将任何小于该大小的CLOB作为VARCHAR 2(4000)(通过CAST)拉取。这比将它们作为CLOB拉取要快得多。但这仍然需要ROWID。
我还应该注意到,虽然这在10多年前给了我相当大的性能提升,超过了Oracle在10 g-11 g时代的原生LOB over dblink,但在最近的版本中,我发现他们已经调整了内部处理,原生LOB传输现在快得多,所以可能不再值得这种黑客式的解决方案。

相关问题