在 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_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
查询任何其他内容的需要。
我有一个类似的查询
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 fromsmall_table
, but I can tweak the SQL to not use it "
根据您发布的 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
查询任何其他内容的需要。