我在Oracle 12c中查询一个大的子分区表,它有关于表和分区级别的统计信息,但没有在子分区级别上收集任何内容。对于不同的分区语法,我得到了明显不同的解释计划结果,可能是因为其中一个依赖于不存在的子分区统计...?我已经通过gather_plan_statistics / dbms_xplan.display_cursor确认实际执行与计划匹配,并且由于其中一个计划使用散列连接和其他嵌套循环,我在这些查询中看到了明显不同的性能。
(它不仅仅是这个特定的生产表。我可以用测试列表范围子分区表,测试索引查找表,少数记录和'全局和分区'dbms_stats重现计划差异。)< / p>
使用扩展分区语法查询1:
select distinct lkt.txt_other
from subpart_test partition(p_2) spt
left join lookup_test lkt on spt.num_other = lkt.num_other
where spt.dt_subkey > to_date('20140101', 'YYYYMMDD')
这为我的子分区表提供了一个基数为1的执行计划;大概是因为它,它使用嵌套循环连接。对于实际行数为55M的生产表分区,平均运行时间不到6分钟。
-----------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
-----------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 17 | 10 (10)| 00:00:01 | | |
| 1 | HASH UNIQUE | | 1 | 17 | 10 (10)| 00:00:01 | | |
| 2 | NESTED LOOPS OUTER | | 1 | 17 | 9 (0)| 00:00:01 | | |
| 3 | PARTITION LIST SINGLE | | 1 | 11 | 8 (0)| 00:00:01 | 2 | 2 |
| 4 | PARTITION RANGE ITERATOR | | 1 | 11 | 8 (0)| 00:00:01 | 3 | 6 |
|* 5 | TABLE ACCESS FULL | SUBPART_TEST | 1 | 11 | 8 (0)| 00:00:01 | 7 | 12 |
| 6 | TABLE ACCESS BY INDEX ROWID BATCHED| LOOKUP_TEST | 2 | 12 | 1 (0)| 00:00:01 | | |
|* 7 | INDEX RANGE SCAN | I_LOOKUP_TEST | 2 | | 0 (0)| 00:00:01 | | |
-----------------------------------------------------------------------------------------------------------------------
使用where子句中的分区键查询2:
select distinct lkt.txt_other
from subpart_test spt
left join lookup_test lkt on spt.num_other = lkt.num_other
where spt.dt_subkey > to_date('20140101', 'YYYYMMDD')
and spt.num_key = 2
这为我提供了具有准确行数估计的执行计划;这会导致散列连接。对于相同的生产表,平均运行时间不到4分钟。 (这是一个2分钟的改进还是33%的改进?只有针对其中一个较大的分区进行测试才能确定,这显然需要更长的时间。)
这也是我为查询1获得的执行计划,如果我在我的测试表上生成子分区的统计信息(我不能在生产中尝试这个),但如果我在分区的where子句中包含分区键则不行规范double whammy:只是拥有partition()语法,没有那些子分区统计信息会与基数估计混淆,无论我做什么。
------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 8 | 160 | 13 (8)| 00:00:01 | | |
| 1 | HASH UNIQUE | | 8 | 160 | 13 (8)| 00:00:01 | | |
|* 2 | HASH JOIN OUTER | | 17 | 340 | 12 (0)| 00:00:01 | | |
| 3 | PARTITION LIST SINGLE | | 10 | 140 | 8 (0)| 00:00:01 | 2 | 2 |
| 4 | PARTITION RANGE ITERATOR| | 10 | 140 | 8 (0)| 00:00:01 | 3 | 6 |
|* 5 | TABLE ACCESS FULL | SUBPART_TEST | 10 | 140 | 8 (0)| 00:00:01 | 7 | 12 |
| 6 | TABLE ACCESS FULL | LOOKUP_TEST | 30 | 180 | 4 (0)| 00:00:01 | | |
------------------------------------------------------------------------------------------------------------
任何人都知道发生了什么以及我如何才能最好地针对没有子分区统计信息的表进行性能调优?它不仅仅是这一张桌子;我有很多像这样的表可以使用相同的模式“查询单个分区,并在连接到其他一些表时在几个子分区的范围内”。目前我正在考虑一种混合策略“问我的DBA与子分区统计数据有什么关系”和“为下一轮性能测试提供散列连接和索引提示”......