我有一个与此类似的查询
select *
from small_table A
inner join huge_table B on A.DATE =B.DATE
huge_table由DATE分区,PK为DATE,some_id和some_other_id(因此连接不是由pk索引完成的)。 small_table只包含几个日期。
SQL的总成本为48分钟
由于某种原因,解释计划给了我一个" PARTITION RANGE(ALL)"在基数上有很高的数字。看起来像是访问整个表,而不仅仅是访问small_table.DATE
指示的分区如果我将SQL放在循环中并执行
for o in (select date from small_table)
loop
select *
from small_table A
inner join huge_table B on A.DATE =B.DATE
where B.DATE=O.DATE
end loop;
仅需2分40秒(完整循环)。 有什么方法可以在Oracle 12c上强制进行分区修剪?
其他信息:
small_table
有13个不同日期的37条记录。 huge_table
拥有8,000,000条记录,包含179个日期/分区。 SQL需要small_table
中的一个字段,但我可以调整SQL以不使用它
更新
使用use_nl hint
,现在执行计划中的基数显示更准确,执行时间从48分钟缩短到4分钟。
select /* use_nl(B) */*
from small_table A
inner join huge_table B on A.DATE =B.DATE
答案 0 :(得分:3)
这似乎是问题所在:
“
small_table
有13个不同日期的37个注册管理机构。huge_table
拥有8.000万个注册管理机构,有179个日期/分区.... SQL需要small_table
中的一个字段,但我可以调整SQL以不使用它“
根据您发布的SQL,您只在DATE列中加入了两个表,没有其他条件。如果确实如此,那么您正在生成一个交叉连接,其中huge_table
的每个分区都加入small_table
2-3次。因此,您的结果集可能比您预期的要大得多,这意味着更多的数据库工作量,这意味着更多的时间。
要注意的另一件事是small_table
到huge_table
分区的基数大约是1:4;优化器不知道实际上只有十三个不同的huge_table
分区在起作用。
优化应该是一门科学,除了尝试这一点之外,这比其他任何事情更多猜测:
select B.*
from ( select /*+ cardinality(t 13) */
distinct t.date
from small_table t ) A
inner join huge_table B
on A.DATE =B.DATE
这应该与优化器通信,只需要一小部分huge_table
分区,这可能会使它选择分区修剪。它也删除了笛卡尔积,这也应该提高性能。显然,您需要应用您提到的调整,以便无需查询small_table
中的任何其他内容。