【发布时间】:2015-02-10 10:40:28
【问题描述】:
当谈到 Oracle 11.2 上的 v$sql_plan_monitor 表时,我遇到了一些奇怪的现象。
我有两张大小合适的桌子。一个有大约 2500 万行,另一个大约有 3500 万行,两者都是约 99% 的唯一性,只有少数几个重复记录。
解释计划如下(表名代替隐私,表在解释计划之前收集了统计信息):
--------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
--------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 65611 (100)| | | | |
| 1 | SORT AGGREGATE | | 1 | 34 | | | | | |
| 2 | PX COORDINATOR | | | | | | | | |
| 3 | PX SEND QC (RANDOM) | :TQ10002 | 1 | 34 | | | Q1,02 | P->S | QC (RAND) |
| 4 | SORT AGGREGATE | | 1 | 34 | | | Q1,02 | PCWP | |
|* 5 | FILTER | | | | | | Q1,02 | PCWC | |
|* 6 | HASH JOIN OUTER | | 234K| 7770K| 65611 (1)| 00:19:41 | Q1,02 | PCWP | |
| 7 | PX RECEIVE | | 23M| 513M| 26409 (1)| 00:07:56 | Q1,02 | PCWP | |
| 8 | PX SEND HASH | :TQ10000 | 23M| 513M| 26409 (1)| 00:07:56 | Q1,00 | P->P | HASH |
| 9 | PX BLOCK ITERATOR | | 23M| 513M| 26409 (1)| 00:07:56 | Q1,00 | PCWC | |
|* 10 | TABLE ACCESS FULL| PRETTY_BIG_TABLE | 23M| 513M| 26409 (1)| 00:07:56 | Q1,00 | PCWP | |
| 11 | PX RECEIVE | | 36M| 384M| 39164 (1)| 00:11:45 | Q1,02 | PCWP | |
| 12 | PX SEND HASH | :TQ10001 | 36M| 384M| 39164 (1)| 00:11:45 | Q1,01 | P->P | HASH |
| 13 | PX BLOCK ITERATOR | | 36M| 384M| 39164 (1)| 00:11:45 | Q1,01 | PCWC | |
|* 14 | TABLE ACCESS FULL| EVEN_BIGGER_TABLE | 36M| 384M| 39164 (1)| 00:11:45 | Q1,01 | PCWP | |
--------------------------------------------------------------------------------------------------------------------------------
让我感到悲伤的数字是Rows 的值HASH JOIN OUTER 步骤。
Oracle 估计它将输出大约 234k 行,这是一个相对较小的数量。我知道查询将在过滤*结果后返回大约 50k 行,因为它之前使用相同的数据运行以进行测试。
*:实际查询本身是反连接,使用LEFT JOIN 和WHERE 过滤NULL 记录。
但是,一旦查询运行,我会在v$sql_plan_monitor 表中检查它的sql_id:
1 SELECT
2 plan_line_id,
3 plan_operation,
4 ROUND(MAX(plan_cardinality) / 1000) AS est_krows,
5 ROUND(SUM(output_rows) / 1000) AS actual_krows
6 FROM v$sql_plan_monitor
7 WHERE sql_id = 'sql_id_goes_here'
8 GROUP BY sql_id, sql_exec_id, sql_exec_start, plan_line_id, plan_operation
9* ORDER BY sql_exec_id, plan_line_id
SQL> /
PLAN_LINE_ID PLAN_OPERATION EST_KROWS ACTUAL_KROWS
------------ ------------------------------ ---------- ------------
0 SELECT STATEMENT 0
1 SORT 0 0
2 PX COORDINATOR 0
3 PX SEND 0 0
4 SORT 0 0
5 FILTER 0
6 HASH JOIN 234 23084866
7 PX RECEIVE 23402 23168
8 PX SEND 23402 23168
9 PX BLOCK 23402 23168
10 TABLE ACCESS 23402 23168
11 PX RECEIVE 36699 17772
12 PX SEND 36699 17748
13 PX BLOCK 36699 17748
14 TABLE ACCESS 36699 17748
请注意,查询仍在进行中,因此actual_krows 的值正在增长。
所以我的问题是:
- 为什么 HASH JOIN 的实际行数相差 5 个数量级?
- 如何才能获得更准确的估计或更准确地读取实际行输出进度?它似乎只是在 JOIN 上给我带来了糟糕的结果,没有别的。
【问题讨论】:
-
您的表中有相关的列吗?即“如果 COL_A 有“1”,那么 COL_B 总是有“X”。当你将反连接重写为不存在子句时会发生什么?
-
@ibre5041 - 据我所知,表上的所有列都没有关联。至于
NOT EXISTS子句,那不是将计划强制纳入NESTED LOOPs 吗?我的印象是它对较大的表有显着的性能影响。
标签: sql oracle performance oracle11g