11g改变了DELETE语句的执行计划

在11.2中,如果DELETE的时候没有限制条件,且表上存在主键的话,执行计划会变为索引全扫。

 

 

在和600聊天的时候听说了这个现象,开始的时候还不是很相信。当时600特意验证了一下,事实确实如此。

于是特意自己也做了个简单的例子:

SQL> select * from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Production
PL/SQL Release 11.2.0.2.0 - Production
CORE 11.2.0.2.0 Production
TNS for Linux: Version 11.2.0.2.0 - Production
NLSRTL Version 11.2.0.2.0 - Production

SQL> create table t_del as select rownum id, a.* from
dba_objects a, user_tables ;

Table created.

SQL> select count(*) from t_del;

  COUNT(*)
----------
    110360

SQL> alter table t_del add primary key (id);

Table altered.

SQL> explain plan for delete t_del;

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------
Plan hash value: 1780357700

--------------------------------------------------------------------------------
| Id  | Operation        | Name        | Rows 
| Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | DELETE STATEMENT |             | 89885 |  1141K|  
245   (1)| 00:00:03 |
|   1 | 
DELETE          | T_DEL       |      
|       |            |          |
|   2 |  
INDEX FULL SCAN| SYS_C006177 | 89885 | 
1141K|   245   (1)| 00:00:03 |
--------------------------------------------------------------------------------

Note
-----
   - dynamic sampling used for this
statement (level=2)

13 rows selected.

SQL> explain plan for delete /*+ full(t_del) */ t_del;

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------
Plan hash value: 2195693323

----------------------------------------------------------------------------
| Id  | Operation          | Name  | Rows 
| Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | DELETE STATEMENT   |      
| 89885 |  1141K|   426  
(1)| 00:00:06 |
|   1 | 
DELETE            | T_DEL |       |      
|            |          |
|   2 |  
TABLE ACCESS FULL| T_DEL | 89885 | 
1141K|   426   (1)| 00:00:06 |
----------------------------------------------------------------------------

Note
-----
   - dynamic sampling used for this
statement (level=2)

13 rows selected.

Oracle认为全索引扫描的代价接近全表扫描的一半,预估时间也只有全表扫描的一半。这中执行计划对于10g以前是不可想象的,既然所有的记录都要处理,通过全表扫描显然是最合适的方法,而通过索引去定位每条记录显然效率要低很多。

那么到底是Oracle改变了实现方式,还是11.2的CBO在这里犯了错误呢,真正执行一下看看效果:

SQL> set timing on
SQL> set autot trace
SQL> delete t_del;

110360 rows deleted.

Elapsed: 00:00:01.23

Execution Plan
----------------------------------------------------------
Plan hash value: 1780357700

--------------------------------------------------------------------------------
| Id  | Operation        | Name        | Rows 
| Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | DELETE STATEMENT |             |     1 |   
13 |   245   (1)| 00:00:03 |
|   1 | 
DELETE          | T_DEL       |      
|       |            |          |
|   2 |  
INDEX FULL SCAN| SYS_C006177 |    
1 |    13 |   245  
(1)| 00:00:03 |
--------------------------------------------------------------------------------

Note
-----
   - dynamic sampling used for this
statement (level=2)

Statistics
----------------------------------------------------------
        247  recursive calls
     124999  db block gets
        395  consistent gets
        270  physical reads
   43099720  redo size
        678  bytes sent via SQL*Net to client
        585  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          2  sorts (memory)
          0  sorts (disk)
     110360  rows processed

SQL> rollback;

Rollback complete.

Elapsed: 00:00:00.92
SQL> delete /*+ full(t_del) */ t_del;

110360 rows deleted.

Elapsed: 00:00:04.63

Execution Plan
----------------------------------------------------------
Plan hash value: 2195693323

----------------------------------------------------------------------------
| Id  | Operation          | Name  | Rows 
| Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | DELETE STATEMENT   |      
|     1 |    13 |  
425   (0)| 00:00:06 |
|   1 | 
DELETE            | T_DEL |       |      
|            |          |
|   2 |  
TABLE ACCESS FULL| T_DEL |     1
|    13 |   425  
(0)| 00:00:06 |
----------------------------------------------------------------------------

Note
-----
   - dynamic sampling used for this statement
(level=2)

Statistics
----------------------------------------------------------
        322  recursive calls
     346841  db block gets
       1731  consistent gets
        593  physical reads
   65160536  redo size
        683  bytes sent via SQL*Net to client
        604  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
     110360  rows processed

SQL> rollback;

Rollback complete.

Elapsed: 00:00:01.69

显然无论从运行时间,还是db
block gets数量,或者是逻辑读或物理读的数量,11.2的全索引扫描执行路径都要远小于全表扫描的方式,甚至连产生的redo的数据量都只有全表扫描的2/3,显然Oracle更改了删除操作的处理机制,才使得全索引扫描这种看上去完全不合理的执行计划可以提高性能。

DELETE操作是Oracle所有DML中代价最大的,看来Oracle认识到了这一点,也在试图改变这种情形。

 

时间: 2024-09-24 14:51:00

11g改变了DELETE语句的执行计划的相关文章

通过分析SQL语句的执行计划优化SQL(二)

优化|语句|执行 第5章 ORACLE的执行计划 背景知识:        为了更好的进行下面的内容我们必须了解一些概念性的术语: 共享sql语句    为了不重复解析相同的SQL语句(因为解析操作比较费资源,会导致性能下降),在第一次解析之后,ORACLE将SQL语句及解析后得到的执行计划存放在内存中.这块位于系统全局区域SGA(system global area)的共享池(shared buffer pool)中的内存可以被所有的数据库用户共享.因此,当你执行一个SQL语句(有时被称为一个

[20120104]稳定一条sql语句的执行计划.txt

[20120104]稳定一条sql语句的执行计划.txt http://www.itpub.net/thread-1495845-1-1.htmlhttp://space.itpub.net/267265/viewspace-723066 ORACLE8I升级11G R2后,查询系统视图特别慢 我的测试版本:SQL> select * from v$version where rownumBANNER------------------------------------------------

SQL Server中如何清除特定语句的执行计划缓存

SQL server运行到一定的时候, 执行计划的缓存可能会相当大,有些能到几个GB的大小.这个时候假设某个语句比较复杂而且SQL server 生成的执行计划不够优化,你希望把该执行计划的缓存清除使得SQL server能够重新编译该语句.该如何做呢? 如果是存储过程则很好办,直接使用sp_recompile就可以了,如下所示.如果参数是表,那么所有用到该表的存储过程或http://www.aliyun.com/zixun/aggregation/17067.html">trigger都

通过分析SQL语句的执行计划优化SQL_MsSql

如何干预执行计划 - - 使用hints提示 基于代价的优化器是很聪明的,在绝大多数情况下它会选择正确的优化器,减轻了DBA的负担.但有时它也聪明反被聪明误,选择了很差的执行计划,使某个语句的执行变得奇慢无比.此时就需要DBA进行人为的干预,告诉优化器使用我们指定的存取路径或连接类型生成执行计划,从而使语句高效的运行.例如,如果我们认为对于一个特定的语句,执行全表扫描要比执行索引扫描更有效,则我们就可以指示优化器使用全表扫描.在Oracle中,是通过为语句添加hints(提示)来实现干预优化器优

通过分析SQL语句的执行计划优化SQL

如何干预执行计划 - - 使用hints提示 基于代价的优化器是很聪明的,在绝大多数情况下它会选择正确的优化器,减轻了DBA的负担.但有时它也聪明反被聪明误,选择了很差的执行计划,使某个语句的执行变得奇慢无比.此时就需要DBA进行人为的干预,告诉优化器使用我们指定的存取路径或连接类型生成执行计划,从而使语句高效的运行.例如,如果我们认为对于一个特定的语句,执行全表扫描要比执行索引扫描更有效,则我们就可以指示优化器使用全表扫描.在Oracle中,是通过为语句添加hints(提示)来实现干预优化器优

Oracle 11g r2全外连接优化执行计划(二) 新增的两个相关的HINT

Oracle在推出了新的执行计划的同时,还提供了两个控制这个执行计划的提示NATIVE_FULL_OUTER_JOIN和NO_NATIVE_FULL_OUTER_JOIN. 这两个HINT的使用十分简单,不需要其他的任何参数.下面继续上一篇文章的例子: SQL> SELECT /*+ NO_NATIVE_FULL_OUTER_JOIN */ T1.ID, T2.ID 2  FROM T1 FULL OUTER JOIN T2 3  ON T1.ID = T2.ID; ID        ID -

Oracle 11g r2全外连接优化执行计划(一)

在11.2中,Oracle对于全外连接的执行计划进行了优化. 在以前的版本中,全外连接的执行计划如下: SQL> SELECT * FROM V$VERSION; BANNER ---------------------------------------------------------------- Oracle Database10gEnterpriseEdition Release10.2.0.3.0 - 64bi PL/SQL Release 10.2.0.3.0 - Product

一条SQL语句的执行计划变化探究

最近有个同事碰到一个问题,想让我给点思路.我大体了解了一下,是一个系统目前在做压力测试,但是经业务反馈发现某个环节的处理时间有些长,排查了一圈,最后这件事情就落在了DB这边,希望DB能够给点意见,是否存在一些性能瓶颈.     我们从开发同学那里得到的一个基本的SQL语句,根据关键字从v$sql中做了提取,发现对应的SQL语句的执行时间还是OK的. 得到的SQL语句如下:SQL_ID        SQL_FULLTEXT ------------- ----------------------

一条SQL语句的执行计划变化探究(r10笔记第9天)

继续上次分析的一个问题,一个简单的SQL语句执行计划有些奇怪,明明可以走唯一性索引但是却走了另外一个索引. 当然了,最后逐步定位,发现是在直方图的地方有一些差别.取消直方图之后,执行计划立刻恢复了正常. 当然问题来了,这个是为什么呢,收集统计信息中的auto选项是什么含义呢.为什么两个数据类型一样的(varchar2(64))的列,境遇却大大不同. 我们来看看一些统计信息的数据. 为了跟进一步验证数据的分布律和选取代价,我们查询它的直方图信息. SQL>   select to_char(end