Oracle:比较包含CLOB和获取差异的表的最快方法

时间:2017-04-25 12:59:44

标签: oracle plsql oracle12c

假设我有两个列,列Col1,Col2和Col3分别为VARCHAR2, CLOB 和NUMBER类型。

如何获得这些表格的差异? (即表B 中存在但不存在于表A 中的记录列表)

Table A:
╔═══════╦═════════════════╦══════╗
║ Col1  ║      Col2       ║ Col3 ║
╠═══════╬═════════════════╬══════╣
║ P1111 ║ some_long_text1 ║ 1234 ║
║ P1111 ║ some_long_text1 ║ 1233 ║
║ P1111 ║ some_long_text2 ║ 1233 ║
╚═══════╩═════════════════╩══════╝

Table B:
╔═══════╦═════════════════╦══════╗
║ Col1  ║      Col2       ║ Col3 ║
╠═══════╬═════════════════╬══════╣
║ P1111 ║ some_long_text1 ║ 1234 ║
║ P1111 ║ some_long_text1 ║ 1235 ║
║ P1112 ║ some_long_text2 ║ 1233 ║
╚═══════╩═════════════════╩══════╝

Expected results:
╔═══════╦═════════════════╦══════╗
║ Col1  ║      Col2       ║ Col3 ║
╠═══════╬═════════════════╬══════╣
║ P1111 ║ some_long_text1 ║ 1235 ║
║ P1112 ║ some_long_text2 ║ 1233 ║
╚═══════╩═════════════════╩══════╝

5 个答案:

答案 0 :(得分:2)

要比较LOB类型,您可以使用DBMS_LOB.COMPARE功能。

SELECT table_b.* 
  FROM table_b
  LEFT JOIN table_a
    ON table_b.col1 = table_a.col1
   AND DBMS_LOB.COMPARE(table_b.col2, table_a.col2) = 0
   AND table_b.col3 = table_a.col3
 WHERE table_a.col1 IS NULL;

答案 1 :(得分:1)

您可以使用dbms_lob.substr()函数,如下所示使用减号运算符

{{1}}

答案 2 :(得分:0)

在Oracle中,我认为你可以做到这一点

SELECT * FROM TableB WHERE (Col1, Col2, Col3) NOT IN (SELECT Col1, Col2, Col3 from TABLEA)

您加入的其他DBS:

SELECT * FROM TableB left outer join TableA 
on (a.Col1=b.Col1 and a.Col2=b.Col2 and a.Col3=b.Col3)
WHERE a.col1 is null

您可能需要在CLOB列上执行校验和/哈希,但是它是否包含在比较中。

答案 3 :(得分:0)

根据您的预期结果,似乎左连接将运作良好。

实现这一点的效果:

Select B.Col1
      ,B.Col2
      ,B,Col3
  FROM TableB B
  LEFT OUTER JOIN TableA A
    ON B.Col1 = A.Col1
 WHERE B.Col2 = A.Col2
   AND B.Col3 = A.Col3
   AND A.Col1 IS NULL

由于WHERE条件会过滤数据集,因此有必要匹配所有内容,包括与表A匹配的NULL值。仅包含A.Col1 IS NULL WHERE然后您确定只能看到TableB中没有相应TableA值的值。

连接很昂贵,而Left Joins更是如此。仅加入一个键值应该有助于提高效率(特别是因为您无论如何都希望匹配所有记录)。通过在WHERE子句中放置其他连接谓词,您可以对这些谓词进行过滤。

现在 - 就CLOB上的匹配而言 - 散列这些值可能有也可能没有任何好处。这取决于数据的大小和使用的散列算法。 Oracle Optimizer可以自动选择对列进行哈希处理以进行比较,也可以使用函数强制它。

我认为引擎应该被允许做出这个选择 - 我相信会有其他人不同意我,他们都有正当理由。我的论点是这样的:如果优化程序可以自己做出这个决定,为什么不强制执行额外的步骤?

如果这将是一个经常被调用的大量使用的查询(例如,作为存储过程),那么创建一个存储CLOB的预先计算的哈希值的列可能会有好处便于比较。这种改变几乎肯定会消除在执行期间要求每个CLOB进行散列的开销,这可能是一个非常CPU密集的操作。我个人不建议索引散列列,因为我希望每个CLOB条目可能是唯一值。如果是这种情况,则表的PK应足以基于行唯一性进行匹配。

答案 4 :(得分:0)

1)您必须为lob对象创建UDT。

create or replace type lob_wrapper is object 
( x clob,
  hash varchar2(100),
 constructor function lob_wrapper(p_x clob)  return self as result,
 MAP MEMBER FUNCTION get_hash  RETURN varchar2

 )
 ;

create  or replace type body lob_wrapper  
as 
 constructor function lob_wrapper(p_x clob)
    return self as result
  as
   temp_ varchar(1000) :=  p_x;
  begin 
       self.x := p_x;
-- add here better implementation of hashing clob. 
       select ora_hash(temp_) into self.hash from dual;   
   return;
  end; 
 MAP MEMBER FUNCTION get_hash  RETURN varchar2 is 
   v_hash varchar2(4000);
 begin    
  return hash;
 end;
end;

对象构造计算clob的哈希值。在示例中,我使用的是ora_hash,但您应该选择更好的解决方案(dbms_crypto.hash)。

当db尝试比较两个对象时,将调用object中的映射函数get_hash

select col1,lob_wrapper(col2) col2 ,col3 from test_clob_b
minus 
select col1,lob_wrapper(col2) col2 ,col3 from test_clob_a

要从对象获取原始值,请添加另一个选择。

select col1,t.col2.x oringal_value,col3, t.col2.hash hash_value from (
select col1,lob_wrapper(col2) col2 ,col3 from test_clob_b
minus 
select col1,lob_wrapper(col2) col2 ,col3 from test_clob_a
) t;