delete 与全表扫描

delete 与全表扫描
先创建一张测试用的表。并填充数据。把表造的大小才有比较的效果。
SQL> create table testing01 (id number(8),col2 varchar2(30));
Table created.
SQL> begin
  2    for i in 1..1000000
  3    loop
  4    insert into testing01 values(i,'This is a testing record');
  5    end loop;
  6    commit;
  7    end;
  8    /   
PL/SQL procedure successfully completed.
通过下面的查询对刚才创建的表有一个基本的认识。
SQL>  select segment_name,blocks,bytes/1024 as "Size[KB]"
  2   from user_segments
  3   where segment_name = 'TESTING01';
SEGMENT_NAME        BLOCKS   Size[KB]
--------------- ---------- ----------
TESTING01             4992      39936
计算HWM(high water mark),所谓的高水位线用来界定segment 中已经使用过的 block 与没有使用的block.已经使用的block 中不一定实际的存储有数据。
SQL>  select blocks from user_segments
  2   where segment_name = 'TESTING01';
    BLOCKS
----------
      4992
SQL>  analyze table testing01 estimate statistics;
Table analyzed.
SQL>  select empty_blocks
  2   from user_tables
  3   where table_name = 'TESTING01';
EMPTY_BLOCKS
------------
          86
hwm =total_blocks – unused_blocks – 1.
HWM=4905
在segment testing01。使用使用过的block 数量是4905.执行如下的查询查看 执行计划。
SQL> set autotrace traceonly
SQL> select * from testing01;
1000000 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 3696461997
-------------------------------------------------------------------------------
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |  1013K|    27M|  1512  (13)| 00:00:19 |
|   1 |  TABLE ACCESS FULL| TESTING01 |  1013K|    27M|  1512  (13)| 00:00:19 |
-------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
      74301  consistent gets
        315  physical reads
     201404  redo size
   43646886  bytes sent via SQL*Net to client
     733745  bytes received via SQL*Net from client
      66668  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
    1000000  rows processed
把表中的记录全部delete ,在确定该表对应的segment 的HWM.
SQL> delete from testing01;
1000000 rows deleted.
SQL>  select blocks from user_segments
  2   where segment_name = 'TESTING01';
    BLOCKS
----------
      4992
SQL>  select blocks from user_segments
  2   where segment_name = 'TESTING01';
    BLOCKS
----------
      4992
SQL>  select empty_blocks
  2   from user_tables
  3   where table_name = 'TESTING01';
EMPTY_BLOCKS
------------
          86
通过查询和使用公式hwm =total_blocks – unused_blocks – 1.
我们可以知道hwm 没有下降,hwm 之所以没有下降的原因是保留
这部分空间为了以后的update,insert 的需要。在这种情况下进行
全部扫描会是怎样的情形呢?
SQL> alter system flush shared_pool;
System altered.
SQL> alter system flush buffer_cache;
System altered.
SQL> select * from testing01;
no rows selected
Execution Plan
----------------------------------------------------------
Plan hash value: 3696461997
-------------------------------------------------------------------------------
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |  1013K|    27M|  1512  (13)| 00:00:19 |
|   1 |  TABLE ACCESS FULL| TESTING01 |  1013K|    27M|  1512  (13)| 00:00:19 |
-------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
        711  recursive calls
          0  db block gets
       4964  consistent gets
       4869  physical reads
          0  redo size
        340  bytes sent via SQL*Net to client
        408  bytes received via SQL*Net from client
          1  SQL*Net roundtrips to/from client
         13  sorts (memory)
          0  sorts (disk)
          0  rows processed
SQL> set autotrace off
我们知道表中没有数据。通过执行计划我们可以知道这条sql 语句在执行的时候还是进行了。 全表扫描读取了很多的数据块。因为oracle 在执行全表扫描的时候会读取对象对应的segment 中第一个block 到HWM之间的blocks。因为delete 不会降低HWM ,所以sql 执行的时候如果
要进行全表扫描,那么oracle 很”无辜“需要多做很多额外的IO操作。为了不让oracle 无辜的 读取那些在HWM下没有数据的block,我们需要尝试降低HWM。可选的方式如下。
1、truncate 一张表,降低HWM 释放空间。如果表空中的数据都不再需要可以选用这种方式。
当时如果我想要删除某些行这种方式就不行了。在很多时候可以结合表分区技术。
2、使用shrink 的方式,但是会导致索引的无效对index 需要rebuilt.步骤比较多。
3、把表drop 了重建。这可能是最烂的方式,因为要考虑到表之间复杂的参照关系,数据的填充 花费的时间和系统资源。
对testing01 进行shrink。我没有创建索引所以不需要对索引进行rebuilt.
SQL> alter table testing01 move;
Table altered.
SQL> select blocks from user_segments
  2   where segment_name = 'TESTING01';
    BLOCKS
----------
         8
SQL> analyze table testing01 estimate statistics;
Table analyzed.
SQL> select empty_blocks
  2   from user_tables
  3   where table_name = 'TESTING01';
EMPTY_BLOCKS
------------
           8
乖乖,现在HWM线下来了回到了表最初创建的时候的样子指向segment 中第一个block的左边。
今日心得
有时候进行全表扫描是好事,或者说是不可避免的。但是在上面这种情况 (或者表中经常进行大量delete 的操作)下就糟糕了,因为oracle 在执行sql 语句的时候 很无辜需要读取高水位线以下的很多空白的block 做无用功。我们应该考虑通过那些方式 避免这种情况的出现。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/26110315/viewspace-722053/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/26110315/viewspace-722053/

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MySQL的DELETE操作速度取决于多个因素,包括表的大小、索引的存在和优化程度、网络延迟(如果在分布式环境中)、以及服务器当前的并发负载。以下是影响DELETE速度的一些关键点: 1. **索引使用**:如果删除操作针对的是带有唯一索引或主键的行,删除通常会更快,因为可以直接定位到要删除的记录。如果没有适当的索引,MySQL可能需要扫描整个表。 2. **锁定机制**:MySQL会对被删除的行加锁,这可能会影响其他并发事务的性能。InnoDB存储引擎使用行级锁定,而MyISAM则使用表级锁定,这可能导致锁定粒度不同对删除速度的影响。 3. **分区和分表**:大型表如果进行了分区或分表,删除操作可能会在特定分区上执行,这样可以减少对整个表的影响。 4. **DELETE FROM...WHERE子句**:明确指定WHERE子句可以提高删除效率,因为它只操作满足条件的行,否则如果删除所有行,MySQL可能需要遍历整张表。 5. **内存缓存**:如果数据被InnoDB缓存在缓冲区内,删除操作可能需要先将数据从缓存中移除。 6. **存储引擎**:不同的存储引擎(如InnoDB、MyISAM)对DELETE操作的处理方式不同,InnoDB通常更快,因为它支持行级锁定和更复杂的事务处理。 为了提高DELETE操作的速度,你可以考虑优化查询,例如创建合适的索引,避免全表扫描,并确保在写入密集的场景下适当管理锁定和并发。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值