如果

时间:2018-11-14 16:45:34

标签: sql oracle performance join

对不起,我的描述很糟糕,但是问题很容易解释。我有一个称为BigTable的大型表(超过20亿行),该表按日期进行分区,如下所示:

ID    Object   Date
---   -------  ----------
1     A         2018-10-01
1     B         2018-10-01 
1     C         2018-10-01
1     D         2018-10-01
2     M         2018-10-01
2     N         2018-10-01
2     O         2018-10-01 
3     X         2018-10-01
3     B         2018-10-01

我需要一个SQL,该SQL返回ID的所有行,其中Object =“ B”和date ='2018-10-01' 因此结果将是:

ID    Object   Date
---   -------  ----------
1     A         2018-10-01
1     B         2018-10-01 
1     C         2018-10-01
1     D         2018-10-01
3     X         2018-10-01
3     B         2018-10-01

SQL很简单,只需将表自身连接起来即可。

SELECT t2.id,t2.object, t2.date
FROM BigTable T1
join BigTable T2 on t2.id = t1.id
   AND t2.transaction_date = '01-OCT-2018'
   AND t2.object = 'B'
where t1.date = '01-OCT-2018'

这会持续运行 HOURS 。子查询并不能使它更好。 为包含对象='B'的ID返回所有行的最有效方式是什么?

3 个答案:

答案 0 :(得分:0)

我认为您已经建立了良好的索引...不能保证这会有所帮助,但是您是否尝试过半联接:

select
  t1.*
from BigTable T1
where
  t1.transaction_date = '01-OCT-2018' and
  exists (
    select null
    from BigTable T2
    where
      t2.transaction_date = t1.transaction_date and
      t2.transaction_date = '01-OCT-2018'
      t2.object = 'B'
)

半联接的优势在于,一旦找到匹配项,它就应该“停止寻找”。

交易日期上的加入似乎是多余的,但是可以两种方式尝试。

答案 1 :(得分:0)

您可以尝试窗口功能:

SELECT t.id, t.object, t.date
FROM (SELECT t.*,
             SUM(CASE WHEN t.object = 'B' THEN 1 ELSE 0 END) OVER (PARTITION BY t.id, t.transaction_date) as cnt
      FROM BigTable t
      WHERE t.transaction_date = DATE '2018-10-01'
     ) t
WHERE cnt > 0;

一种可能是您对分区有误解,并且查询中正在读取表的全部内容。

答案 2 :(得分:0)

在与日期进行比较时,应避免直接使用日期字符串。隐式转换的原因可能并不总是在日期上使用可用分区。 Data type conversion的文档指出

  

隐式转换算法可能会随着时间的推移而变化   软件版本以及Oracle产品中。显式行为   转化更容易预测。

     

如果在索引表达式中发生隐式数据类型转换,则   Oracle数据库可能不使用索引,因为它是为   转换前的数据类型。这可能会对   性能。

因此,最好使用ANSI标准日期文字

SELECT t2.id,t2.object, t2.date
FROM BigTable T1
join BigTable T2 on t2.id = t1.id
   AND t2.transaction_date = DATE '2018-10-01'
   AND t2.object = 'B'
where t1.date = DATE '2018-10-01'

此外,正如注释中已经建议的那样,在LOCAL INDEX上创建(date, id, transaction_date, object),以使用索引和分区修剪功能进一步提高扫描速度。