在 Oracle 上强制分区修剪

Force partition pruning on Oracle

我有一个类似的查询

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(所以join不是按pk索引)。 small_table 只包含几个日期。

SQL 的总费用是 48 分钟

由于某种原因,解释计划给了我一个 "PARTITION RANGE (ALL)",基数很高。看起来可以访问完整的 table,而不仅仅是 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 有 80 亿条记录,其中 179 dates/partitions。 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

这似乎是问题所在:

"small_table have 37 registries for 13 different dates. huge_table has 8.000 millions of registries with 179 dates/partitions.... The SQL need one field from small_table, but I can tweak the SQL to not use it "

根据您发布的 SQL,您只是在没有附加条件的情况下在它们的 DATE 列上连接了两个表。如果确实如此,您将生成一个交叉连接,其中 huge_table 的每个分区都连接到 small_table 2-3 次。因此您的结果集可能比您预期的要大得多,这意味着更多的数据库工作,这意味着更多的时间。

要注意的另一件事是 small_tablehuge_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 查询任何其他内容的需要。