为什么优化程序计划与实验性查询运行不相关?

为什么优化程序计划与实验性查询运行不相关?

问题描述:

假设我们有以下问题:为什么优化程序计划与实验性查询运行不相关?

  • 给定一个表有一列'X',含有某些行随机 整数从1到100:

    CREATE TABLE xtable(x) AS 
        SELECT ceil(dbms_random.value * 100) 
        FROM dual 
        CONNECT BY level <= 1000000; 
    
  • 我们必须删除重复所以所有不同的整数都保留在表中。


让我们考虑三种解决方案(平均执行时间和优化计划)之下。

我必须补充,实验表明:

  • 溶液1和2是可伸缩的,并具有与每个行量步骤(附表测试高达10万行)
  • 溶液3具有线性时间的增长指数时间增长大约像3 * exp(0.6 * N)

我们看到,对于解决方案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

+0

当你说“不能信任案例2中的优化器计划”时,你是什么意思?你认为2和3的执行计划是相似的吗?执行计划3有两个嵌套循环半连接的全表扫描,然后进行过滤。执行计划2排序后跟一个过滤器,然后用它来过滤全表扫描的结果。这与第一个执行计划IMHO更相似。 – Boneist

+0

@Boneist,我认为列的行,字节,成本,时间的总值的相似性。令人惊讶的是它们几乎相同,并且当我们用不同数量的行填充表时发生同步变化:1000,10 000,...,10 000 000 – diziaq

+0

加上一个好的准备好Q.请提供Oracle版本并添加*谓词信息*给解释计划。见[这里](http://*.com/questions/34975406/how-to-describe-performance-issue-in-relational-database?answertab=active#tab-top)如何获取信息。 –

请解释为什么我不能在案件2

你不应该相信优化信任优化计划。 CBO是95%,但你不知道哪5%是错的。

典型问题是使用EXPLAIN PLAN显示的执行计划不等于执行使用的计划。 (你不说你如何获得这个计划)。

有疑问请使用DBMS_SQLTUNE.REPORT_SQL_MONITOR来查看实际计划和有问题的零件。

是什么导致优化器忽略线性和指数复杂度之间的明显差异?

看到上面,忘了计划的成本比较。在处理整个表时要避免的是处理NESTED LOOP。 这是情况3

| 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| 

你想看排序和哈希加入这个是啥子计划1所示究竟发生了什么。

在我看来,计划2将与重复记录的数量不成比例(简单地尝试一个表,每行两次,看看你是否获得与案例3相同的经过时间)。 优化程序无法估计重复记录的数量,因此可以防御性地估计出高数量,因此成本高。

最后一个备注 - 理论说,你不应该观察线性特性但充其量O(n * log(n))

最后的评论 - 您的测试数据对于删除dups不现实。典型的你有一个大的桌子,只有少数几个人。在你的设置中,除100以外的所有记录都是dups。

删除成本占主导地位找到dups的成本,所以你观察线性行为。

CREATE TABLE xtable(x) AS 
    SELECT ceil(dbms_random.value * 100000000) 
    FROM dual 
    CONNECT BY level <= 1000000; 

select count(*) total, count(*)- count(distinct x) to_be_deleted from xtable; 
    TOTAL TO_BE_DELETED 
---------- ------------- 
    1000000   5083 

努力让您将删除的记录0.5%。现在规模化,你会完全观察其他模式。

+0

感谢您提供有用的信息。我同意O(n * log(n)),但令人惊讶的结果是100,000行:1.65秒; 1,000,000行 - 15.8; 10,000,000-138.6秒;甚至比预期的还要低。我认为低质量的测试数据会抵消常见的理论影响。 – diziaq

+0

@diziaq补充说明 –

得到无法重现的第二个计划。这里说到:

-------------------------------------------------------------------------------------------          
| Id | Operation    | Name  | Rows | Bytes |TempSpc| Cost (%CPU)| Time  |          
-------------------------------------------------------------------------------------------          
| 0 | DELETE STATEMENT  |   |  |  |  | 3648 (100)|   |          
| 1 | DELETE    | XTABLE |  |  |  |   |   |          
| 2 | MERGE JOIN ANTI NA |   | 999K| 26M|  | 3648 (5)| 00:00:01 |          
| 3 | SORT JOIN   |   | 1000K| 2929K| 22M| 3147 (3)| 00:00:01 |          
| 4 |  TABLE ACCESS FULL | XTABLE | 1000K| 2929K|  | 434 (3)| 00:00:01 |          
|* 5 | SORT UNIQUE   |   | 100 | 2500 |  | 500 (16)| 00:00:01 |          
| 6 |  VIEW    | VW_NSO_1 | 100 | 2500 |  | 499 (16)| 00:00:01 |          
| 7 |  SORT GROUP BY  |   | 100 | 300 |  | 499 (16)| 00:00:01 |          
| 8 |  TABLE ACCESS FULL| XTABLE | 1000K| 2929K|  | 434 (3)| 00:00:01 |          
-------------------------------------------------------------------------------------------   
+0

它看起来像我所期望的。似乎是我的数据库有一个异常或棘手的设置或别的东西。现在并不重要。困扰我的事情是如何确定DB将执行查询的方式。我很困惑,因为之前从未遇到过这样的问题,并且认为EXPLAIN PLAN至少近似地显示了查询运行时会发生什么。 – diziaq

+0

@diziaq你有什么Oracle版本?我已经在11和12测试了它,执行计划是相同的(当我们不计算成本时)。你将永远无法确定。您可以使用SQL计划基线 – Mottor

+0

我昨天和今天多次使用不同的实例在Oracle 12.1上获得了计划。在提出这个问题之后,我对Oracle 11.2进行了相同的查询,并且和您一样,我无法重现所问的计划。所以它看起来像一个意外,但我想知道是什么原因造成的。 – diziaq