对不起,我的描述很糟糕,但是问题很容易解释。我有一个称为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返回所有行的最有效方式是什么?
答案 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)
,以使用索引和分区修剪功能进一步提高扫描速度。