需要从表1中获取表2中没有的数据

时间:2015-07-07 06:08:45

标签: sql oracle performance query-optimization

我需要找到与其他表中的数据匹配的数据。 我创建的示例查询是:

SELECT 
    a.TOTAL_TYPE, a.ACCOUNT_ID, a.CALLING_NUMBER, a.CALLED_NUMBER, a.C_NUMBER, a.CALL_DURATION, a.CALL_DATE_TIME, 
    a.USAGE_AMT, a.BATCH_NUMBER, a.PROCESSING_MONTH, a.BILL_CYCLE_START_DATE 
FROM 
    EMCESU.V_BIL_USAGE_EVENT_MAJOR a, EMCESU.TTY_ANALYSIS_PR2 c 
where
    c.account_id = '702297500' AND
    a.account_id = c.account_id and
    c.total_type = 344  AND
    a.total_type = c.total_type and 
    (substr(a.calling_number,2), substr(a.called_number,2), a.call_date_time, to_char(a.total_type)) 
       not in  (select 
                substr(b.s_p_number_address,4), substr(b.o_p_number_address,4), b.start_time_timestamp+(b.start_time_offset/86400), 
                to_char(b.TECHN_INFO_ETIS_total_TYPE) 
                    from EMCESU.RTX_TTY_COMPARISON_DROP5_PR2 b 
                    where cust_info_customer_id = c.CUSTOMER_ID and 
                          b.TECHN_INFO_ETIS_total_TYPE = '344')
;

有人可以用其他更好的方式帮助我。

2 个答案:

答案 0 :(得分:2)

请使用NOT EXISTS来提高性能,而不是使用NOT IN。截至目前我已经重新编写了查询,但我目前没有工作表,因此可能存在一些语法错误,但逻辑仍然相同。

    SELECT a.TOTAL_TYPE,
      a.ACCOUNT_ID,
      a.CALLING_NUMBER,
      a.CALLED_NUMBER,
      a.C_NUMBER,
      a.CALL_DURATION,
      a.CALL_DATE_TIME,
      a.USAGE_AMT,
      a.BATCH_NUMBER,
      a.PROCESSING_MONTH,
      a.BILL_CYCLE_START_DATE
    FROM EMCESU.V_BIL_USAGE_EVENT_MAJOR a,
      EMCESU.TTY_ANALYSIS_PR2 c
    WHERE c.account_id = '702297500'
    AND a.account_id   = c.account_id
    AND c.total_type   = 344
    AND a.total_type   = c.total_type
    AND NOT EXISTS
      (SELECT 1 FROM EMCESU.RTX_TTY_COMPARISON_DROP5_PR2 b
      WHERE cust_info_customer_id                            = c.CUSTOMER_ID
      AND b.TECHN_INFO_ETIS_total_TYPE                       = '344'
      AND SUBSTR(b.s_p_number_address,4)                     = SUBSTR(a.calling_number,2)
      AND SUBSTR(b.o_p_number_address,4)                     = SUBSTR(a.called_number,2)
      AND b.start_time_timestamp+(b.start_time_offset/86400) = a.call_date_time
      AND TO_CHAR(b.TECHN_INFO_ETIS_total_TYPE)              = TO_CHAR(a.total_type)
      );

答案 1 :(得分:2)

有几种不同的方法可以在一个表中查找与另一个表中的记录不匹配的记录。

第一个是你拥有的那个,NOT IN:

 select * from t1
 where t1.col1 not in ( select t2.col1 from t2);

接下来是略有不同的NOT EXISTS:

select * from t1
where not exists ( select null from t2
                   where t1.col1 = t2.col1 );

这是两个非常不同的查询:如果子查询结果中的任何行为NULL,NOT IN将返回零行,而NOT EXISTS将匹配非NULL记录。

上面有一个变种,ANTI-JOIN:

select t1.* from t1
left outer join t2 on t1.col1 = t2.col1
where t2.col1 is null;

最后还有MINUS操作:

select t1.col1 from t1
minus
select t2.col1 from t2;

这些都不是“最好的”:它实际上取决于了解您的数据。当我们知道子查询将返回零行时,ANTI JOIN是高效的。当子查询保证不包含空值时,NOT IN是有效的。当我们对差异化列感兴趣时,MINUS运算符非常有效。当我们怀疑子查询可能包含空值时,NOT EXISTS是有效的。

除此之外,它就像调整任何其他查询一样。很大程度上取决于了解数据的数量,分布和偏差。主查询返回多少条记录?子查询返回多少条记录?我们倾向于假设子查询返回一小组记录,因此NOT EXISTS是最佳选择。但事实并非如此。如果两个结果集的大小相似,您可能会发现ANTI JOIN是更好的选择。

因此。使用EXPLAIN PLAN了解优化程序正在进行的选择。理解表的索引。确保您的统计信息准确无误。 Find out more