Delete删除表数据时对性能的影响分析

标签: delete 删除 数据 | 发表时间:2014-09-28 06:29 | 作者:aaron8219
出处:http://blog.csdn.net
上一篇博客中提到,当我们用delete删除数据时,因为无法降低高水位,对表做全表扫描时会带来数据库性能问题,而truncate可以大大改善这一状况,下面来看测试

SQL> conn zlm/zlm
Connected.

--创建表之前先记录下剩余表空间大小
SQL> select * from dba_free_space where tablespace_name='ZLM';

TABLESPACE_NAME                   FILE_ID   BLOCK_ID      BYTES     BLOCKS RELATIVE_FNO
------------------------------ ---------- ---------- ---------- ---------- ------------
ZLM                                     6        128   51380224       6272            6

--创建一个100W行的大表
SQL> create table test1(int number);

Table created.

SQL> analyze table test1 compute statistics;

Table analyzed.

SQL> select table_name,num_rows,blocks,empty_blocks,avg_row_len,last_analyzed from dba_tables where table_name like 'TEST%';

TABLE_NAME                       NUM_ROWS     BLOCKS EMPTY_BLOCKS AVG_ROW_LEN LAST_ANALYZED
------------------------------ ---------- ---------- ------------ ----------- ------------------
TEST1                                   0          0            0           0 27-SEP-14

注意,创建完表结构而未插入数据时,表的高水位是0,并没有为该表分配任何数据块

SQL> declare
  2  i number := 0;
  3  begin
  4  for i in 1 .. 1000000 loop
  5  insert into test1 values (i);
  6  end loop;
  7  commit;
  8  end;
  9  /

PL/SQL procedure successfully completed.

SQL> select count(*) from test1;

  COUNT(*)
----------
   1000000

--查看高水位状况
SQL> select header_file,header_block,bytes,blocks,extents from dba_segments where segment_name like 'TEST%';

HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS    EXTENTS
----------- ------------ ---------- ---------- ----------
          6          130   13631488       1664         28

SQL> select block_id,extent_id,bytes,blocks from dba_extents where segment_name like 'TEST%';

  BLOCK_ID  EXTENT_ID      BYTES     BLOCKS
---------- ---------- ---------- ----------
       128          0      65536          8
       136          1      65536          8
       144          2      65536          8
       152          3      65536          8
       160          4      65536          8
       168          5      65536          8
       176          6      65536          8
       184          7      65536          8
       192          8      65536          8
       200          9      65536          8
       208         10      65536          8
       216         11      65536          8
       224         12      65536          8
       232         13      65536          8
       240         14      65536          8
       248         15      65536          8
       256         16    1048576        128
       384         17    1048576        128
       512         18    1048576        128
       640         19    1048576        128
       768         20    1048576        128
       896         21    1048576        128
      1024         22    1048576        128
      1152         23    1048576        128
      1280         24    1048576        128
      1408         25    1048576        128
      1536         26    1048576        128
      1664         27    1048576        128

SQL> select * from dba_free_space where tablespace_name='ZLM';

TABLESPACE_NAME                   FILE_ID   BLOCK_ID      BYTES     BLOCKS RELATIVE_FNO
------------------------------ ---------- ---------- ---------- ---------- ------------
ZLM                                     6       1792   37748736       4608            6

SQL> set autot trace
SQL> select count(*) from test1;


Execution Plan
----------------------------------------------------------
Plan hash value: 3896847026

--------------------------------------------------------------------
| Id  | Operation          | Name  | Rows  | Cost (%CPU)| Time     |
--------------------------------------------------------------------
|   0 | SELECT STATEMENT   |       |     1 |     2   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |       |     1 |            |          |
|   2 |   TABLE ACCESS FULL| TEST1 |     1 |     2   (0)| 00:00:01 |
--------------------------------------------------------------------


Statistics
----------------------------------------------------------
          0  recursive calls
          1  db block gets
       1599  consistent gets
          0  physical reads
          0  redo size
        526  bytes sent via SQL*Net to client
        519  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

SQL> delete from test1;

1000000 rows deleted.


Execution Plan
----------------------------------------------------------
Plan hash value: 2642947686

--------------------------------------------------------------------
| Id  | Operation          | Name  | Rows  | Cost (%CPU)| Time     |
--------------------------------------------------------------------
|   0 | DELETE STATEMENT   |       |     1 |     2   (0)| 00:00:01 |
|   1 |  DELETE            | TEST1 |       |            |          |
|   2 |   TABLE ACCESS FULL| TEST1 |     1 |     2   (0)| 00:00:01 |
--------------------------------------------------------------------


Statistics
----------------------------------------------------------
        814  recursive calls
    1038983  db block gets
       1953  consistent gets
          8  physical reads
  245334988  redo size
        847  bytes sent via SQL*Net to client
        769  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
    1000000  rows processed

用delete删除100W行数据的大表TEST1时,产生了大量的redo(2亿多),另外还有很多一致性读(1953),读取了100多W个数据块,814次递归调用,可以看到,用delete删除表记录,对数据库的性能消耗是很大的,尤其是当delete大量行的时候

SQL> set autot off
SQL> select count(*) from test1;

  COUNT(*)
----------
         0

SQL> select header_file,header_block,bytes,blocks,extents from dba_segments where segment_name like 'TEST%';

HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS    EXTENTS
----------- ------------ ---------- ---------- ----------
          6          130   13631488       1664         28

--用delete删除数据后查看执行计划
SQL> set autot trace
SQL> select count(*) from test1;


Execution Plan
----------------------------------------------------------
Plan hash value: 3896847026

--------------------------------------------------------------------
| Id  | Operation          | Name  | Rows  | Cost (%CPU)| Time     |
--------------------------------------------------------------------
|   0 | SELECT STATEMENT   |       |     1 |     2   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |       |     1 |            |          |
|   2 |   TABLE ACCESS FULL| TEST1 |     1 |     2   (0)| 00:00:01 |
--------------------------------------------------------------------


Statistics
----------------------------------------------------------
          0  recursive calls
          1  db block gets
       1599  consistent gets
          0  physical reads
          0  redo size
        525  bytes sent via SQL*Net to client
        519  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

此时虽然表中已经没有一条记录了,但是由于TEST1表并没有索引,走的是全表扫描,全表扫描就是要从hearder_block的值一致扫描到blocks得值,即从block 130一致到block 1664,可以看到,即使去访问一个空表,也要消耗1599次逻辑读,这就是高水位没有下降的缘故,之前说过,delete操作并不会降低表的高水位,带来的副作用就是访问该表时带来的性能下降(产生大量逻辑读)

--truncate表后再次查看统计信息
SQL> truncate table test1;

Table truncated.

SQL> set autot trace
SQL> select count(*) from test1;


Execution Plan
----------------------------------------------------------
Plan hash value: 3896847026

--------------------------------------------------------------------
| Id  | Operation          | Name  | Rows  | Cost (%CPU)| Time     |
--------------------------------------------------------------------
|   0 | SELECT STATEMENT   |       |     1 |     2   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |       |     1 |            |          |
|   2 |   TABLE ACCESS FULL| TEST1 |     1 |     2   (0)| 00:00:01 |
--------------------------------------------------------------------


Statistics
----------------------------------------------------------
          2  recursive calls
          1  db block gets
          7  consistent gets
          0  physical reads
         96  redo size
        525  bytes sent via SQL*Net to client
        519  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

此时再去全表扫描TEST1表,只有7次一致性读了,大大降低了需要扫描的数据库块,只有1个,

--查看此时TEST1表的表信息
SQL> select table_name,num_rows,blocks,empty_blocks,avg_row_len,last_analyzed from dba_tables where table_name like 'TEST%';

TABLE_NAME                       NUM_ROWS     BLOCKS EMPTY_BLOCKS AVG_ROW_LEN LAST_ANALYZED
------------------------------ ---------- ---------- ------------ ----------- ------------------
TEST1                                   0          0            0           0 27-SEP-14

--似乎不太准确,重新收集一下统计信息
SQL> analyze table test1 compute statistics;

Table analyzed.

--再次查看
SQL> select table_name,num_rows,blocks,empty_blocks,avg_row_len,last_analyzed from dba_tables where table_name like 'TEST%';

TABLE_NAME                       NUM_ROWS     BLOCKS EMPTY_BLOCKS AVG_ROW_LEN LAST_ANALYZED
------------------------------ ---------- ---------- ------------ ----------- ------------------
TEST1                                   0          0            8           0 27-SEP-14

可以看到,truncate已经把高水位降低到8了,而且是8个空块(EMPTY_BLOCKS),表示高水位以下未使用的空间,即第一个EXTENT为TEST1表分配的BLOCK空间,并且是最低值了,这与我们刚才是创建的只有表结构的空表不一样,同样是没有行数据的表,刚才创建表结构时的高水位为0。因此可以这么说,truncate降低高水位的作用也是有限的,还是剩余了1个extent的blocks的高水位,并没有完全消除。如果默认1个extent的block要大于8,那么高水位也要超过8

SQL> select header_file,header_block,bytes,blocks,extents from dba_segments where segment_name like 'TEST%';

HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS    EXTENTS
----------- ------------ ---------- ---------- ----------
          6          130      65536          8          1

dba_segment视图也可以反映这一高水位的情况,如果对表做全表扫描,就是从130开始,扫描8个数据块,而并非之前的从130扫描到1664了

--查看剩余表空间容量
SQL> select * from dba_free_space where tablespace_name='ZLM';

TABLESPACE_NAME                   FILE_ID   BLOCK_ID      BYTES     BLOCKS RELATIVE_FNO
------------------------------ ---------- ---------- ---------- ---------- ------------
ZLM                                     6        136   51314688       6264            6

truncate表数据后,ZLM剩余表空间又变大了,但是要注意,又多了8个block的消耗,建表之前查看的BLOCK_ID值是128

总结:

delete删除数据会读取大量的数据块,并产生大量的redo,对数据库产生性能影响,尤其是对大表操作时,删除大量的行数据时,而truncate虽然可以有效降低高水位,但其也有一定的局限性:
1. 并不能完全消除空表的高水位,仍然会有一定的空间浪费(8K)
2. 无法用于非清空全表数据的删除的场景


作者:aaron8219 发表于2014-9-27 22:29:37 原文链接
阅读:93 评论:0 查看评论

相关 [delete 删除 数据] 推荐:

Delete删除表数据时对性能的影响分析

- - CSDN博客数据库推荐文章
上一篇博客中提到,当我们用delete删除数据时,因为无法降低高水位,对表做全表扫描时会带来数据库性能问题,而truncate可以大大改善这一状况,下面来看测试. --创建表之前先记录下剩余表空间大小. ZLM                                     6        128   51380224       6272            6.

为什么MySQL不建议delete删除数据

- - 掘金后端本月最热
有情怀,有干货,微信搜索【. 三太子敖丙】关注这个不一样的程序员. github.com/JavaFamily 已收录,有一线大厂面试完整考点、资料以及我的系列文章. 我负责的有几个系统随着业务量的增长,存储在MySQL中的数据日益剧增,我当时就想现在的业务方不讲武德,搞偷袭,趁我没反应过来把很多表,很快,很快啊都打到了亿级别,我大意了,没有闪,这就导致跟其Join的表的SQL变得很慢,对的应用接口的response time也变长了,影响了用户体验.

oracle恢复删除的数据(转载)

- - 数据库 - ITeye博客
oracle恢复删除的数据. 分为两种方法:scn和时间戳两种方法恢复. 一、通过scn恢复删除且已提交的数据.   1、获得当前数据库的scn号.     select current_scn from v$database; (切换到sys用户或system用户查询).     查询到的scn号为:1499223.

delete 清空表之后,磁盘空间未发生变化?

- - SegmentFault 最新的文章
上篇文章结尾和小伙伴们留了一个小问题,就是关于 optimize table 命令,今天我想花点时间再来和小伙伴们聊一聊这个话题. 我现在有一个名为 sakila 的数据库,该库中有一个 film 表,这个表中有 1000 条记录,我么先来看下这 1000 条记录占用了多少存储空间:. 小伙伴们可以看到,这个文件大小是 360448 个字节.

SQL调优:Clustering Factor影响数据删除速度一例

- Maclean - Oracle Clinic - 提供专业Oracle技术支持,性能调整及数据恢复服务
事情是这样的,客户有一套核心的10g业务数据库,需要针对个别大表删除2年前的归档数据,这些表都是普通的堆表(heap table),没有使用分区或其他技术. 因为考虑到不能影响在线业务,所以不能使用insert append/rename的方式来加速删除,只能老老实实地在匿名PL/SQL块里通过rowid批量删除数据,虽然慢一些但还是能接受的,具体的PL/SQL块如下:.

java实现hbase表创建、数据插入、删除表

- - 学着站在巨人的肩膀上
近日查看了相关资料后,梳理了一下用java实现hbase的表创建、数据插入、删除表,代码如下:. 类别: Hadoop  查看评论.

【转】恢复ORACLE被误更新或删除数据的办法

- - Oracle - 数据库 - ITeye博客
有时候我们在操作ORACLE数据库的时候,可能由于SQL写错了导致把数据update错了,或者delete删除掉了,那么这时候如何去恢复之前的数据呢. 莫着急,我们可以采用oracle的基于时间查询as of timestamp的办法进行恢复数据. 1、比如,我的wl_notify_task表目前有三条数据,大家重点关注PARAMETER字段.

数据库优化-删除不再使用的索引

- - CSDN博客数据库推荐文章
一个运行了四年的库,近期发现一些头疼的问题,空间不足,性能降低. 发现有些索引因为应用变更,基本不用了,决定检测,删除那些不同的索引;. 以前也有写过博文: http://blog.csdn.net/jacson_bai/article/details/37773319. 这里涉及到公司一些安全,就不贴出来了,主要说一下解决思路.

从Gitlab误删除数据库想到的

- - 酷 壳 – CoolShell
昨天,Gitlab.com发生了一个大事,某同学误删了数据库,这个事看似是个低级错误,不过,因为Gitlab把整个过程的细节都全部暴露出来了,所以,可以看到很多东西,而对于类似这样的事情,我自己以前也干过,而在最近的两公司中我也见过(Amazon中见过一次,阿里中见过至少四次),正好通过这个事来说说一下自己的一些感想和观点吧.

Chrome OS 会在磁盘空间不足之时自动删除用户数据

- delphij - 谷奥——探寻谷歌的奥秘
在最新版的Chrome OS Dev分支 (14.0.835.87) 里,文件管理器最底部多出了一行提示,说:. 警告:这些临时文件可能会被自动删除以释放磁盘空间. 如果你的Chromebook磁盘空间不多的时候,你的浏览器数据会被自动删除. 在需要额外空间的时候,超过3个月没登录过的非拥有者帐户的信息都会被删除(包括下载的文件).