【发布时间】:2016-11-06 23:44:20
【问题描述】:
假设我们有以下问题:
-
给定一个包含一列
'X'的表,其中包含一些随机的行 从 1 到 100 的整数:CREATE TABLE xtable(x) AS SELECT ceil(dbms_random.value * 100) FROM dual CONNECT BY level <= 1000000; 我们必须删除重复的行,以便所有不同的整数都保留在表中。
让我们考虑下面的三个解决方案(平均执行时间和优化器计划)。
我必须补充一下实验表明:
- 解决方案 1 和 2 具有可扩展性,并且随着每个行数量步骤的增加而线性时间增长(使用多达 1000 万行的表进行测试)
- 解决方案 3 具有指数时间增长,大致类似于
3 * exp(0.6 * N)
我们看到对于solution 2优化器计划给出与实验结果无关的期望, 甚至与他们相反:
- 计划 2 和 3 中的成本和其他值几乎相同
- 解决方案 1 和 2 的执行时间几乎相同
在这个实验中,表的收集统计信息的存在与否 不会影响优化器计划和执行时间。
请解释为什么我不能信任案例 2 中的优化器计划。
是什么导致优化器忽略了线性复杂度和指数复杂度之间的明显区别?
解决方案:
1.
DELETE xtable WHERE rowid IN (
SELECT ri from (
SELECT rowid AS ri,
row_number() OVER(PARTITION BY x ORDER BY null) AS rn
FROM xtable
)
WHERE rn > 1
)
Exe time: 14 - 16 secs
Plan:
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost | Time |
------------------------------------------------------------------------------------
| 0 | DELETE STATEMENT | | 1000000 | 15000000 | 5119 | 00:00:01 |
| 1 | DELETE | XTABLE | | | | |
| * 2 | HASH JOIN SEMI | | 1000000 | 15000000 | 5119 | 00:00:01 |
| 3 | TABLE ACCESS FULL | XTABLE | 1000000 | 3000000 | 280 | 00:00:01 |
| 4 | VIEW | VW_NSO_1 | 1000000 | 12000000 | 2976 | 00:00:01 |
| * 5 | VIEW | | 1000000 | 25000000 | 2976 | 00:00:01 |
| 6 | WINDOW SORT | | 1000000 | 3000000 | 2976 | 00:00:01 |
| 7 | TABLE ACCESS FULL | XTABLE | 1000000 | 3000000 | 280 | 00:00:01 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
------------------------------------------
* 2 - access(ROWID="RI")
* 5 - filter("RN">1)
2.
DELETE xtable WHERE (x, rowid) NOT IN (SELECT x, min(rowid) FROM xtable GROUP BY x)
Exe time: 15 - 17 secs
Plan:
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost | Time |
--------------------------------------------------------------------------------------
| 0 | DELETE STATEMENT | | 50000 | 150000 | 278162850 | 03:01:06 |
| 1 | DELETE | XTABLE | | | | |
| 2 | FILTER | | | | | |
| 3 | TABLE ACCESS FULL | XTABLE | 1000000 | 3000000 | 281 | 00:00:01 |
| 4 | FILTER | | | | | |
| 5 | SORT GROUP BY NOSORT | | 1000000 | 3000000 | 280 | 00:00:01 |
| 6 | TABLE ACCESS FULL | XTABLE | 1000000 | 3000000 | 280 | 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
------------------------------------------
* 5 - access(INTERNAL_FUNCTION("X")=INTERNAL_FUNCTION("X") AND INTERNAL_FUNCTION(ROWID)=INTERNAL_FUNCTION("MIN(ROWID)"))
* 5 - filter(INTERNAL_FUNCTION(ROWID)=INTERNAL_FUNCTION("MIN(ROWID)") AND INTERNAL_FUNCTION("X")=INTERNAL_FUNCTION("X"))
3.
DELETE xtable a WHERE EXISTS(select 1 FROM xtable b WHERE a.x = b.x AND a.rowid < b.rowid)
Exe time: 970 - 990 sec
Plan:
----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost | Time |
----------------------------------------------------------------------------------------------
| 0 | DELETE STATEMENT | | 50000 | 300000 | 278208956 | 03:01:08 |
| 1 | DELETE | XTABLE | | | | |
| * 2 | FILTER | | | | | |
| 3 | NESTED LOOPS SEMI | | 50000 | 300000 | 278208956 | 03:01:08 |
| 4 | TABLE ACCESS FULL | XTABLE | 1000000 | 3000000 | 280 | 00:00:01 |
| * 5 | TABLE ACCESS BY ROWID RANGE | XTABLE | 50000 | 150000 | 278 | 00:00:01 |
----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
------------------------------------------
* 2 - filter(:VAR2=:VAR1)
* 5 - access("B".ROWID>"A".ROWID)
计划是在Oracle 12.1.0.2.0获得的
【问题讨论】:
-
当您说“在情况 2 中不能信任优化器计划”时,您是什么意思?是什么让您认为 2 和 3 的执行计划相似?执行计划 3 有两个全表扫描,由嵌套循环半连接,然后过滤。执行计划 2 有一个排序,后跟一个过滤器,然后使用它来过滤全表扫描的结果。这更类似于第一个执行计划,恕我直言。
-
@Boneist,我考虑了 Rows、Bytes、Cost、Time 列中 Total 值的相似性。令人惊讶的是,它们几乎相同,并且当我们用不同数量的行填充表时同步变化:1000、10 000、...、10 000 000
-
加一个很好的准备Q。请提供Oracle版本并在解释计划中添加谓词信息。获取信息见here。
标签: oracle database-performance oracle12c sqlperformance cost-based-optimizer