Delete不释放高水位线的问题,与truncate对比实验
Oracle高水位线 HWM对数据库影响:
1. 全表扫描通常要读取直到HWM标记内,所有属于该表数据库块,即使该表中没有任何数据,这样将耗费更多的I/O资源;
2. 即使HWM以下有空闲的数据库块,键入在插入数据时使用了append关键字,则在插入时使用HWM以上的数据块,此时HWM会自动增大;
3. 优点,可使HWM以下的数据块重复利用。
----实验-----------------------------------------------------------------------
1. 建表
Create table test_0412 as
select * from user_objects;
2. 查看统计信息
select t.BLOCKS, t.NUM_ROWS
from user_tables t
where t.TABLE_NAME = 'TEST_0412';
结果为空,说明系统没有收集到统计信息。
查看段信息:
select blocks from user_segments where segment_name='TEST_0412';
--结果说明数据已保存至段:
BLOCKS 8
-------------------------------------------------------------------------------
Select * from test_0412;
没有统计信息情况下,看执行计划,走的全表扫描,逻辑读为1,物理读为38,如下:
Execution Plan
----------------------------------------------------------
Plan hash value: 3552262383
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 41 | 7790 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS FULL| TEST_0412 | 41 | 7790 | 3 (0)| 00:00:01 |
-------------------------------------------------------------------------------
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
288 recursive calls
0 db block gets
38 consistent gets
1 physical reads
0 redo size
5210 bytes sent via SQL*Net to client
545 bytes received via SQL*Net from client
4 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
41 rows processed
3. 收集统计信息
SQL> Exec dbms_stats.gather_table_stats(user,'TEST_0412');
PL/SQL procedure successfully completed.
4. 二次查看统计信息是否收集成功
select t.BLOCKS, t.NUM_ROWS
from user_tables t
where t.TABLE_NAME = 'TEST_0412';
结果:
BLOCKS 4
NUM_ROWS 41
---
查看段信息:
select blocks from user_segments where segment_name='TEST_0412';
--结果说明统计信息收集对段无影响:
BLOCKS 8
---
alter session set events 'immediate trace name flush_cache';--清空缓存
Select * from test_0412;
看执行计划,走全表扫描,逻辑读为2,物理读为6,如下:
Execution Plan
----------------------------------------------------------
Plan hash value: 3552262383
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 41 | 3075 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS FULL| TEST_0412 | 41 | 3075 | 3 (0)| 00:00:01 |
-------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
6 consistent gets
2 physical reads
0 redo size
5210 bytes sent via SQL*Net to client
545 bytes received via SQL*Net from client
4 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
41 rows processed
5. Delete数据,清空表
delete from TEST_0412;
Commit;
SQL> Exec dbms_stats.gather_table_stats(user,'TEST_0412');
PL/SQL procedure successfully completed.
6. 三次查看统计信息
select t.BLOCKS, t.NUM_ROWS
from user_tables t
where t.TABLE_NAME = 'TEST_0412';
结果:
BLOCKS 4
NUM_ROWS 41
---
查看段信息:
select blocks from user_segments where segment_name='TEST_0412';
--结果说明段无影响:
BLOCKS 8
---
证明了Delete操作没有更新高水位线,即没有更新段信息。
Oracle全表扫描的机制:扫描HWM(高水位线)下的所有数据块,而delete操作不会释放高水位线。
同问,Truncate操作可以更新高水位线吗?可参看第8步骤操作。
7. 查询全表,看执行计划,是否全表扫描,逻辑读和物理读是多少?
虽然结果是0行,但还是有逻辑读、物理读等消耗,如下:
SQL> select * from test_0412;
no rows selected
Execution Plan
----------------------------------------------------------
Plan hash value: 3552262383
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 41 | 3075 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS FULL| TEST_0412 | 41 | 3075 | 3 (0)| 00:00:01 |
-------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
3 consistent gets
2 physical reads
0 redo size
1276 bytes sent via SQL*Net to client
512 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
8. Truncate操作可以更新高水位线吗?
truncate table TEST_0412;
SQL> Exec dbms_stats.gather_table_stats(user,'TEST_0412');
PL/SQL procedure successfully completed.
select t.BLOCKS, t.NUM_ROWS
from user_tables t
where t.TABLE_NAME = 'TEST_0412';
--结果已重新收集:
BLOCKS 0
NUM_ROWS 0
---
查看段信息:
select blocks from user_segments where segment_name='TEST_0412';
--结果说明Truncate对段无影响:
BLOCKS 8
结果证明truncate操作可更新高水位线HWM。
9. 如何降低高水位线?
alter table TEST_0412 move; --move压缩高水位线HWM以下的空间,消除碎片,move操作后需对索引rebuild
Exec dbms_stats.gather_table_stats(user,'TEST_0412');
select t.BLOCKS, t.NUM_ROWS
from user_tables t
where t.TABLE_NAME = 'TEST_0412';
--结果重新收集:
BLOCKS 0
NUM_ROWS 0
---
查看段信息:
select blocks from user_segments where segment_name='TEST_0412';
--结果段无影响:
BLOCKS 8
10. 再次查询全表,看执行计划,是否全表扫描,逻辑读和物理读
SQL> alter session set events 'immediate trace name flush_cache'; --清空缓存
SQL> select * from test_0412;
no rows selected
Execution Plan
----------------------------------------------------------
Plan hash value: 3552262383
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 190 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS FULL| TEST_0412 | 1 | 190 | 2 (0)| 00:00:01 |
-------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
3 consistent gets
1 physical reads
0 redo size
1276 bytes sent via SQL*Net to client
512 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
从以上结果看出,统计信息收集是否正确,对执行计划影响是非常大的。