最近,bi同事的反馈指出了一张表的数据查询速度非常慢,尽管该表的数据总量不足1万行。我们首先考虑的是高水位线(hwm)带来的性能问题,即高水位线下占用了大量数据块,而这些数据块中大部分是空闲的。
我们知道,在全表扫描时,高水位线下的所有数据块都会被扫描,因此扫描的数据块数量可能远远超过实际存储数据的数据块数量。
一、收集表的统计信息
要获取准确的高水位信息,首先需要收集统计信息,这样得到的信息才会相对准确。
ANALYZE TABLE table_name ESTIMATE STATISTICS; ANALYZE TABLE table_name COMPUTE STATISTICS FOR TABLE FOR ALL INDEXES FOR ALL INDEXED COLUMNS; execute dbms_stats.gather_table_stats(ownname => 'OWNER', tabname => 'TABLE_NAME', estimate_percent => null, method_opt => 'for all indexed columns', cascade => true);
二、查看表信息
查看表的块和行信息:
select t.TABLE_NAME, t.NUM_ROWS, t.BLOCKS, t.empty_blocks, t.LAST_ANALYZED from dba_tables t where table_name in ('TABLE_NAME');
SELECT COUNT(DISTINCT DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)) USED_BLOCK FROM TABLE_NAME;
上述查询结果显示,当前表的行数为9651行,HWM下的数据块使用了716119个,而未使用的数据块为0个。
实际数据占用的数据块数量为152个。
从中可以看出,高水位线下有716119-152个数据块可以释放,这样每次全表扫描只需扫描152个数据块即可。
通过查看段大小来验证记录数和表大小是否一致,段大小为5.5G,9651行的记录几乎不可能达到这个大小,因此可以断定其中有很多空闲块。
select segment_name, bytes/1024/1024/1024 TSize_GB from dba_segments where segment_name='table_name' ---5876219904

三、问题原因
什么情况下会导致上述问题,即高水位线下存在大量未使用的数据块?通常是大表(插入大量记录后)经过批量删除操作(delete),未释放高水位线所致。
四、降低高水位的方法
alter table table_name move; 此方法可以释放高水位,但需要重建索引。alter table table_name shrink space; 此方法可以释放高水位,但在执行前需要启用行移动:alter table table_name enable row movement;
alter table table_name deallocate unused; 此方法用于释放HWM上方的未使用空间,但不会释放HWM下方的自由空间,也不会移动HWM的位置。五、高水位调整实施
SQL> set autotrace trace; SQL> set timing on; SQL> SELECT count(*) FROM TABLE_NAME;

alter table table_name move;
报错:ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired 查看被锁对象:
select object_name, machine, s.sid, s.serial# from v$locked_object l, dba_objects o, v$session s where l.object_id=o.object_id and l.session_id=s.sid;
执行后再查看执行计划统计信息:

可以看到,统计信息中访问的数据块已经减少,全表扫描速度也大大提升。
alter index index_name rebuild online;
六、库高水位对象统计
①比较表的行数和表的大小关系。如果行数为0,而表的当前占用大小减去初始化时的大小(INITIAL_EXTENT)后依然很大,说明该表有高水位。
②行数和块数的比率,即查看一个块可以存储多少行数据。如果一个块存储的行数少于5行甚至更少,说明有高水位。注意,这两种方法都不是十分准确,需要对查询结果进行进一步筛选。在查询表的高水位时,首先需要分析表,以获取最准确的统计信息。
SELECT D.OWNER, ROUND(D.NUM_ROWS / D.BLOCKS, 2), D.NUM_ROWS, D.BLOCKS, D.TABLE_NAME, ROUND((d.BLOCKS*8-D.INITIAL_EXTENT/1024)/1024) t_size FROM DBA_TABLES D WHERE D.BLOCKS > 10 AND ROUND(D.NUM_ROWS / D.BLOCKS, 2) < 5 AND D.NUM_ROWS > 50 AND OWNER NOT LIKE '%SYS%' AND BLOCKS > 100 ORDER BY WASTE_PER DESC;
以上就是Oracle实例之HWM(高水位线)性能优化的详细内容,更多请关注php中文网其它相关文章!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号