由数据库的HWM想起的对ArcSDE数据库的性能优化
在Oracle数据的存储中,可以把存储空间想象为一个水库,数据想象为水库中的水。水库中的水的位置有一条线叫做水位线,在Oracle中,这条线被称为高水位线(High-warter mark, HWM)。在数据库表刚建立的时候,由于没有任何数据,所以这个时候水位线是空的,也
在Oracle数据的存储中,可以把存储空间想象为一个水库,数据想象为水库中的水。水库中的水的位置有一条线叫做水位线,在Oracle中,这条线被称为高水位线(High-warter mark, HWM)。在数据库表刚建立的时候,由于没有任何数据,所以这个时候水位线是空的,也就是说HWM为最低值。当插入了数据以后,高水位线就会上涨,但是这里也有一个特性,就是如果你采用delete语句删除数据的话,数据虽然被删除了,但是高水位线却没有降低,还是你刚才删除数据以前那么高的水位。也就是说,这条高水位线在日常的增删操作中只会上涨,不会下跌。HWM通常增长的幅度为一次5个数据块.
Select语句会对表中的数据进行一次扫描,但是究竟扫描多少数据存储块呢,这个并不是说数据库中有多少数据,Oracle就扫描这么大的数据块,而是Oracle会扫描高水位线以下的数据块。现在来想象一下,如果刚才是一张刚刚建立的空表,你进行了一次Select操作,那么由于高水位线HWM在最低的0位置上,所以没有数据块需要被扫描,扫描时间会极短。而如果这个时候你首先插入了一千万条数据,然后再用delete语句删除这一千万条数据。由于插入了一千万条数据,所以这个时候的高水位线就在一千万条数据这里。后来删除这一千万条数据的时候,由于delete语句不影响高水位线,所以高水位线依然在一千万条数据这里。这个时候再一次用select语句进行扫描,虽然这个时候表中没有数据,但是由于扫描是按照高水位线来的,所以需要把一千万条数据的存储空间都要扫描一次,也就是说这次扫描所需要的时间和扫描一千万条数据所需要的时间是一样多的。所以有时候有人总是经常说,怎么我的表中没有几条数据,但是还是这么慢呢,这个时候其实奥秘就是这里的高水位线了。
那有没有办法让高水位线下降呢,其实有一种比较简单的方法,那就是采用TRUNCATE语句进行删除数据。采用TRUNCATE语句删除一个表的数据的时候,类似于重新建立了表,不仅把数据都删除了,还把HWM给清空恢复为0。所以如果需要把表清空,在有可能利用TRUNCATE语句来删除数据的时候就利用TRUNCATE语句来删除表,特别是那种数据量有可能很大的临时存储表。
---------------------感谢http://blog.csdn.net/tianlesoftware的相关总结
那么由数据库Oracle的高水位线来延伸到我们的ArcSDE数据库,我们在进行编辑,不管是版本编辑或者是非版本编辑,都有可能进行删除操作,更新也是删除再新增的过程,那么如果用户的编辑操作删除占的比重比较大时,就面临着上面所说的问题,更不要说有可能有用户出现将整个要素类的要素全部删除的情况,那么HWM的情况就需要我们注意了。
我们来做个实验,我在数据库中导入一个要素类,然后将要素全表删除掉,我们看看有什么情况发生。
导入之后我们查看图层记录
SQL> select count(*) from zd; COUNT(*) ---------- 4555我们查看一下这个图层(表)所有分配的Block
SQL> select segment_name,segment_type,blocks from user_segments where segment_name='ZD'; SEGMENT_NAME SEGMENT_TYPE BLOCKS --------------------------------------------------------------------------------- ------------------ ---------- ZD TABLE 256然后我们进行ArcGIS的分析操作
SQL> select table_name,num_rows,blocks,empty_blocks from user_tables where table_name='ZD'; TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS ------------------------------ ---------- ---------- ------------ ZD 4555 244 0经过分析之后,我们可以看到图层的行数已经要素所占的Blocks,但是empty_blocks为空,我们可以使用Oracle的分析功能来实现。(注意,ArcGIS的分析功能其实是调用了 dbms_stats的存储过程,和Oracle本身分析有区别)
SQL> analyze table ZD compute statistics; 表已分析。 SQL> select table_name,num_rows,blocks,empty_blocks from user_tables where table_name='ZD'; TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS ------------------------------ ---------- ---------- ------------ ZD 4555 244 12然后我们将整个要素类的数据进行非版本编辑的删除
SQL> select count(*) from zd; COUNT(*) ---------- 0 SQL> select segment_name,segment_type,blocks from user_segments where segment_name='ZD'; SEGMENT_NAME SEGMENT_TYPE BLOCKS --------------------------------------------------------------------------------- ------------------ ---------- ZD TABLE 256 SQL> select table_name,num_rows,blocks,empty_blocks from user_tables where table_name='ZD'; TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS ------------------------------ ---------- ---------- ------------ ZD 4555 244 12由上面可以看到,虽然我们的表里面的记录已经为空了,但是所占用的Blocks仍然存在,那么由上面的概念表述所说,我们在进行查询的时候不是看表里面的记录多少,而是针对某个表所占的blocks进行搜索,如果上面的情况,那么无疑我们消耗了大量的无效的系统资源。
我们可以使用Trucate表的方法来处理
SQL> truncate table zd; 表被截断。 SQL> select segment_name,segment_type,blocks from user_segments where segment_name='ZD'; SEGMENT_NAME SEGMENT_TYPE BLOCKS --------------------------------------------------------------------------------- ------------------ ---------- ZD TABLE 8 SQL> select table_name,num_rows,blocks,empty_blocks from user_tables where table_name='ZD'; TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS ------------------------------ ---------- ---------- ------------ ZD 4555 244 12虽然所占用的blocks变成默认的8KB了,但是我们的统计信息没有改变,我们需要重新统计一下
SQL> exec dbms_stats.gather_table_stats('TEST','ZD'); PL/SQL 过程已成功完成。 SQL> select table_name,num_rows,blocks,empty_blocks from user_tables where table_name='ZD'; TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS ------------------------------ ---------- ---------- ------------ ZD 0 0 12 SQL> analyze table ZD compute statistics; 表已分析。 SQL> select table_name,num_rows,blocks,empty_blocks from user_tables where table_name='ZD'; TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS ------------------------------ ---------- ---------- ------------ ZD 0 0 8从上面的实验我们可以将HWM的知识体会的比较深。
但是在现实的业务中并不是将某些表全部删除,而是进行部分的删除,那么我们可以使用另外一种方法来处理。
在上面的例子的基础上,我删除了若干条记录,然后进行统计分析
SQL> select table_name,num_rows,blocks,empty_blocks from user_tables where table_name='ZD'; TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS ------------------------------ ---------- ---------- ------------ ZD 571 244 12我们可以看到,在没有经过任何处理情况下,只有行数变化了,所占用的blocks和emptry_blocks都是和原来一样,那么我们进行
SQL> alter table zd move; 表已更改。然后在进行重新统计
SQL> exec dbms_stats.gather_table_stats('TEST','ZD'); BEGIN dbms_stats.gather_table_stats('TEST','ZD'); END; * 第 1 行出现错误: ORA-20000: index "TEST"."R132_SDE_ROWID_UK" or partition of such index is in unusable state ORA-06512: 在 "SYS.DBMS_STATS", line 20337 ORA-06512: 在 "SYS.DBMS_STATS", line 20360 ORA-06512: 在 line 1提示ZD表中的R132_SDE_ROWID_UK索引对象有问题,需要注意一下,当我们进行了上面的move操作之后,我们必须对索引(这个索引是属性索引)进行重建
SQL> alter index R132_SDE_ROWID_UK rebuild online; 索引已更改。 SQL> exec dbms_stats.gather_table_stats('TEST','ZD'); PL/SQL 过程已成功完成。 SQL> analyze table ZD compute statistics; 表已分析。 SQL> select table_name,num_rows,blocks,empty_blocks from user_tables where table_name='ZD'; TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS ------------------------------ ---------- ---------- ------------ ZD 571 24 0这样的话,才能看到实际的结果。
那么如果是版本编辑,找到相关的A表、D表,操作应该是类似的。
----------------------------------------------------------
说明:针对上面实验,我们可以针对某个我们常编辑的图层,而且定位到这个图层的效率很低,我们可以看看是不是跟HWM有关系,其实上面讲的如果没有听明白,没有关系,最简单的方法,将你的效率低的图层,导出来到FGDB里面,然后数据库删除掉该图层,再导进去,其实变相的就没有这种负担了.前提你不再大量编辑了。
推荐阅读
-
面向程序员的数据库访问性能优化法则
-
浅析Facebook对MySQL数据库的深度优化
-
MySQL数据库性能优化之避免数据死锁的发生
-
sql server数据库性能优化之2-避免使用CTE公用表达式的递归【by zhang502219048】
-
sql server数据库性能优化之1-慎用distinct避免不必要的distinct【by zhang502219048】
-
Oracle数据库Where条件执行顺序及Where子句的条件顺序对性能的影响分析
-
MySQL性能优化的一些技巧帮助你的数据库_MySQL
-
对MySQL数据库查询进行优化的方法有哪些?
-
对MySQL数据库查询进行优化的方法有哪些?
-
MySQL数据库性能优化的关键参数_MySQL