Oracle 降低高水位线的方法
高水位(HIGH WARTER MARK,HWM)好比水库中储水的水位,用于描述数据库中段的扩展方式。高水位对全表扫描方式有着至关重要的影响。当使用DELETE删除表记录时,高水位并不会下降,随之导致的是全表扫描的实际开销并没有任何减少。
例如,首先新建一张空表,大小占用64K,然后插入数据直到表大小变为50G,此时使用DELETE删除所有的数据并且提交,这个时候查询表的大小的时候依然是50G,这就是因为表的高水位没有释放的缘故,而在这时如果使用“SELECT * FROM TABLE_NAME;”语句来查询数据的话,那么查询过程就会很慢,因为Oracle要执行全表扫描,从高水位下所有的块都得去扫描,直到50G的所有块全部扫描完毕。曾遇到一个同事使用DELETE删除了一个很大的分区表,然后执行SELECT查询很久都没有结果,以为是数据库HANG住了,其实这个问题是由于高水位的缘故。所以,表执行了TRUNCATE操作,再次SELECT的时候就可以很快返回结果了。
释放表的高水位通常有如下几种办法:
(1)对表进行MOVE操作:ALTER TABLE TABLE_NAME MOVE;。若表上存在索引,则记得重建索引。
(2)对表进行SHRINK SPACE操作:ALTER TABLE TABLE_NAME SHRINK SPACE;,注意,在执行该指令之前必须开启行移动:ALTER TABLE TABLE_NAME ENABLE ROW MOVEMENT;。该方法的优点是:在碎片整理结束后,表上相关的索引仍然有效,缺点是会产生大量的UNDO和REDO。
(3)复制要保留的数据到临时表T,DROP原表,然后RENAME临时表T为原表。
(4)exp/imp或expdp/impdp重构表。
(5)若表中没有数据则直接使用TRUNCATE来释放高水位。
如何找出系统中哪些表拥有高水位呢?这里给出两种办法,①比较表的行数和表的大小关系。如果行数为0,而表的当前占用大小减去初始化时的大小(INITIAL_EXTENT)后依然很大,那么说明该表有高水位。②行数和块数的比率,即查看一个块可以存储多少行数据。如果一个块存储的行数少于5行甚至更少,那么说明有高水位。注意,这两种方法都不是十分准确,需要再对查询结果进行筛选。需要注意的是,在查询表的高水位时,首先需要分析表,以得到最准确的统计信息。
下面给出用于查询高水位的几个SQL语句:
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.OWNER NOT LIKE '%SYS%' ; 或: SELECT OWNER, SEGMENT_NAME TABLE_NAME, SEGMENT_TYPE, GREATEST(ROUND(100 * (NVL(HWM - AVG_USED_BLOCKS, 0) / GREATEST(NVL(HWM, 1), 1)), 2), 0) WASTE_PER FROM (SELECT A.OWNER OWNER, A.SEGMENT_NAME, A.SEGMENT_TYPE, B.LAST_ANALYZED, A.BYTES, B.NUM_ROWS, A.BLOCKS BLOCKS, B.EMPTY_BLOCKS EMPTY_BLOCKS, A.BLOCKS - B.EMPTY_BLOCKS - 1 HWM, DECODE(ROUND((B.AVG_ROW_LEN * NUM_ROWS * (1 + (PCT_FREE / 100))) / C.BLOCKSIZE, 0), 0, 1, ROUND((B.AVG_ROW_LEN * NUM_ROWS * (1 + (PCT_FREE / 100))) / C.BLOCKSIZE, 0)) + 2 AVG_USED_BLOCKS, ROUND(100 * (NVL(B.CHAIN_CNT, 0) / GREATEST(NVL(B.NUM_ROWS, 1), 1)), 2) CHAIN_PER, B.TABLESPACE_NAME O_TABLESPACE_NAME FROM SYS.DBA_SEGMENTS A, SYS.DBA_TABLES B, SYS.TS$ C WHERE A.OWNER = B.OWNER AND SEGMENT_NAME = TABLE_NAME AND SEGMENT_TYPE = 'TABLE' AND B.TABLESPACE_NAME = C.NAME) WHERE GREATEST(ROUND(100 * (NVL(HWM - AVG_USED_BLOCKS, 0) / GREATEST(NVL(HWM, 1), 1)), 2), 0) > 50 AND OWNER NOT LIKE '%SYS%' AND BLOCKS > 100 ORDER BY WASTE_PER DESC;
最后再次提醒各位读者,若表执行了大量的DELETE操作后,则最好回收一下表的高水位。
http://docs.oracle.com/cd/E11882_01/server.112/e40540/logical.htm#CNCPT89022
Segment Space and the High Water Mark
To manage space, Oracle Database tracks the state of blocks in the segment. The high water mark (HWM) is the point in a segment beyond which data blocks are unformatted and have never been used.
MSSM uses free lists to manage segment space. At table creation, no blocks in the segment are formatted. When a session first inserts rows into the table, the database searches the free list for usable blocks. If the database finds no usable blocks, then it preformats a group of blocks, places them on the free list, and begins inserting data into the blocks. In MSSM, a full table scan reads allblocks below the HWM.
ASSM does not use free lists and so must manage space differently. When a session first inserts data into a table, the database formats a single bitmap block instead of preformatting a group of blocks as in MSSM. The bitmap tracks the state of blocks in the segment, taking the place of the free list. The database uses the bitmap to find free blocks and then formats each block before filling it with data. ASSM spread out inserts among blocks to avoid concurrency issues.
Every data block in an ASSM segment is in one of the following states:
-
Above the HWM
These blocks are unformatted and have never been used.
-
Below the HWM
These blocks are in one of the following states:
-
Allocated, but currently unformatted and unused
-
Formatted and contain data
-
Formatted and empty because the data was deleted
-
Figure 12-23 depicts an ASSM segment as a horizontal series of blocks. At table creation, the HWM is at the beginning of the segment on the left. Because no data has been inserted yet, all blocks in the segment are unformatted and never used.
Figure 12-23 HWM at Table Creation
Description of "Figure 12-23 HWM at Table Creation"
段空间和高水位标记 |
oracle数据库通过跟踪段中的块状态来管理空间。高水位标记(HWM)是段中的一个点,超过该点的数据块是未格式化和未使用过的。 |
MSSM使用空闲列表来管理段空间。在创建表时,段中的块并未被格式化。当一个会话初次向表中插入行时,数据库将搜索空闲列表来查找可用的块。如果数据库未找到可用的块,那么它会预格式化一组块,并将它们放置在空闲列表中,并开始将数据插入到块中。在MSSM中,全表扫描会读取HWM之下的所有块。 |
ASSM不使用空闲列表,所以必须以不同的方式管理空间。当会话初次向表中插入数据时,数据库只格式化一个单一位图块,而不像在MSSM中那样预格式化一组块。位图取代了空闲列表,用于跟踪在段中的块的状态。数据库使用位图来查找可用的块,然后在往块写入数据之前将其格式化。ASSM将插入操作分散到多个块,以避免并发问题。 |
在一个ASSM段中的每个数据块处于以下状态之一: |
l 在HWM之上 这些块是未格式化的,且从未使用过。 l 在HWM之下 这些块处于以下状态之一: u 已分配,但当前未格式化且未使用 u 已格式化且包含数据 u 已格式化且为空,因为数据已被删除 |
图12-23将一个ASSM段描述为一系列水平的块。在创建表时,HWM在左侧段的开头。因为还未插入数据,段中的所有块都还是未格式化且从未使用过。 |
图将12-23在创建表时的HWM |
Suppose that a transaction inserts rows into the segment. The database must allocate a group of blocks to hold the rows. The allocated blocks fall below the HWM. The database formats a bitmap block in this group to hold the metadata, but does not preformat the remaining blocks in the group.
In Figure 12-24, the blocks below the HWM are allocated, whereas blocks above the HWM are neither allocated or formatted. As inserts occur, the database can write to any block with available space. The low high water mark (low HWM) marks the point below which all blocks are known to be formatted because they either contain data or formerly contained data.
In Figure 12-25, the database chooses a block between the HWM and low HWM and writes to it. The database could have just as easily chosen any other block between the HWM and low HWM, or any block below the low HWM that had available space. In Figure 12-25, the blocks to either side of the newly filled block are unformatted.
The low HWM is important in a full table scan. Because blocks below the HWM are formatted only when used, some blocks could be unformatted, as in Figure 12-25. For this reason, the database reads the bitmap block to obtain the location of the low HWM. The database reads all blocks up to the low HWM because they are known to be formatted, and then carefully reads only the formatted blocks between the low HWM and the HWM.
Assume that a new transaction inserts rows into the table, but the bitmap indicates that insufficient free space exists under the HWM. In Figure 12-26, the database advances the HWM to the right, allocating a new group of unformatted blocks.
When the blocks between the HWM and low HWM are full, the HWM advances to the right and the low HWM advances to the location of the old HWM. As the database inserts data over time, the HWM continues to advance to the right, with the low HWM always trailing behind it. Unless you manually rebuild, truncate, or shrink the object, the HWM never retreats.
See Also:
-
Oracle Database Administrator's Guide to learn how to shrink segments online
-
Oracle Database SQL Language Reference for TRUNCATE TABLE syntax and semantics
假设一个事务将行插入到段中。数据库必须分配一组块来容纳这些行。已分配的块在HWM之下。数据库格式化该组中的一个位图块来容纳元数据,但不会预格式化组中其余的块。
在图12-24中,HWM之下的块是已分配的,而HWM之上的块是既未分配也未格式化的。插入发生时,数据库可以写入到任何具有可用空间的块。由低位高水位标记(低HWM)标记一个点,该点之下的所有块都已知是已格式化的,要么包含数据,或以前曾包含数据。
在图12-25中,数据库选定了HWM和低HWM之间的一个块,并往其中写入数据。数据库也可能会随意选择HWM和低HWM之间的任何其他块,或低HWM之下任何有可用空间的块。图12-25中,在新填充块两边的块都还是未格式化的。
低HWM在全表扫描中非常重要。因为HWM之下的块只在被使用时才格式化,所以可能还有一些块是未被格式化的,如图12-25所示。鉴于此,数据库读取位图块,以获取低HWM的位置。数据库读取低HWM之下的所有块,因为已知它们是已格式化的,然后仅仔细读取位于低 HWM 和 HWM 之间的已格式化块。
假定一个新事务将行插入到该表,但位图指示在HWM之下没有足够的可用空间。在图12-26中,数据库向右推进HWM,分配一组新的未格式化块。
当HWM与低HWM之间的块填满时,HWM向右推进,而低HWM相应推进到旧的HWM的位置。数据库不断插入数据,随着时间的推移,HWM继续向右推进,而低HWM总尾随其后。除非您手动重建、截断、或缩小该对象,否则HWM从不倒退。
备注: 1)move不但可以重置水位线(HWM),解决松散表带来的 IO 浪费,还可以解决表中的行迁移问题。 move表的话需要双倍的空间,否则无法成功。move表可以通过重新安排数据文件的空间达到收缩数据文件的目的。 move表时,会产生exclusive lock 锁,此时只能对表进行 select 操作。 move表之后,如果表上有索引,记得重建。 2)shrink表只对ASSM管理的表有效,相关命令有: -----alter table TABLE_NAME shrink space; 整理碎片并回收空间 -----alter table TABLE_NAME shrink space compact; 只整理碎片,不回收空间 -----alter table TABLE_NAME shrink space cascate; 整理碎片回收空间,并连同表的级联对象一起整理(比如索引) 能在线进行,不影响表上的DML操作,当然,并发的DML操作在shrink结束的时刻会出现短暂的block; shrink的另外一个优点是在碎片整理结束后,表上相关的index仍然enable。 3)move的操作速度远远快于shrink 操作 ,不是一般的快,不是一个数量级的,而且shrink 会产生大量的undo 和redo 操作。 4)truncate是DDL操作,相当于删表后重建。 5)还有其他的方法,如导出后再重新导入。
详细转自:http://blog.itpub.net/26736162/viewspace-2139546/