- 浏览: 4411620 次
- 性别:
- 来自: 厦门
文章分类
- 全部博客 (634)
- Oracle日常管理 (142)
- Oracle体系架构 (45)
- Oracle Tuning (52)
- Oracle故障诊断 (35)
- RAC/DG/OGG (64)
- Oracle11g New Features (48)
- DataWarehouse (15)
- SQL, PL/SQL (14)
- DB2日常管理 (9)
- Weblogic (11)
- Shell (19)
- AIX (12)
- Linux/Unix高可用性 (11)
- Linux/Unix日常管理 (66)
- Linux桌面应用 (37)
- Windows (2)
- 生活和工作 (13)
- 私人记事 (0)
- Python (9)
- CBO (15)
- Cognos (2)
- ORACLE 12c New Feature (2)
- PL/SQL (2)
- SQL (1)
- C++ (2)
- Hadoop大数据 (5)
- 机器学习 (3)
- 非技术 (1)
最新评论
-
di1984HIT:
xuexilee!!!
Oracle 11g R2 RAC高可用连接特性 – SCAN详解 -
aneyes123:
谢谢非常有用那
PL/SQL的存储过程和函数(原创) -
jcjcjc:
写的很详细
Oracle中Hint深入理解(原创) -
di1984HIT:
学习了,学习了
Linux NTP配置详解 (Network Time Protocol) -
avalonzst:
大写的赞..
AIX内存概述(原创)
热块概述
当一个会话需要访问一个数据块,而这个数据块正在被另一个用户从磁盘读取到内存中或者这个数据块正在被另一个会话修改时,当前的会话就需要等待,就会产生一个buffer busy waits等待,也伴随着Latch争用。如果太多的会话去访问相同的数据块导致长时间的
buffer busy waits等待
,通常表现形式为CPU使用率很高,但吞吐量很低。造成热快的原因可能是数据库设置导致或者重复执行的SQL 频繁访问一些相同的数据块导致。热块产生的原因不尽相同,按照数据块的类型,可以分成以下几种热块类型,不同热块类型处理的方式都是不同的:表数据块、索引数据块、索引根数据块、文件头数据块和数据块自身的争用。
表数据块
比如在OLTP系统中,对于一些小表,会出现某些数据块被频繁查询或者修改的操作,这时候这些被频繁访问的数据块就会变成热块,导致内存中Latch的争用。
如果出现这样的热块情况,并且表不太大,一个方法是可以考虑将表数据分布在更多的数据块上,减少数据块被多数会话同时访问的频率。
可以通过下面的命令将每个数据块存放记录的数量减到最少:
alter table minimize records_per_block;
我们也可以通过调大PCTFREE来实现,不过在调整PCTFREE时,
我们要注意的是,这个参数虽然是可以动态调整的,但是我们调整PCTFREE参数只能对新的数据插入起作用,对于已经填充过满的老数据块,是无法起作用的,数据分布问题,必须调整参数后,对表进行重组,才能对表中的所有数据块都起作用。对表重组的办法有很多,比如ALTER TABLE ... MOVE或者EXP/IMP等。
除了调整
PCTFREE外,
减少热块冲突的更好的办法是将这张表放在BLOCK_SIZE较小的表空间里。以上所有的方法都是将数据尽可能地分布到多个数据块为指导思想进行实现的。
请看下面的例子,创建两个数据量相同的表,让一个表上每个数据块存放记录数尽可能地小,另一个表保持默认的情况,来看数据块访问情况:
SQL> create table t as select * from dba_objects;
Table created.
SQL> create index t_inx on t(object_id);
Index created.
SQL> exec dbms_stats.gather_table_stats(‘HR','T',cascade=>true);
PL/SQL procedure successfully completed.
SQL> select 'T' tbl_name, rows_per_block,
count(*) number_of_such_blocks from (
2 select dbms_rowid.ROWID_BLOCK_NUMBER
( rowid ), count(*) rows_per_block
3 from t
4 group by dbms_rowid.ROWID_BLOCK_NUMBER( rowid ))
5 group by 'T', rows_per_block;
--- -------------- ---------------------
T 82 16
T 76 18
T 74 22
T 77 16
T 65 3
T 87 2
T 84 5
T 69 76
T 93 2
T 91 1
T 75 20
TB1 ROWS_PER_BLOCK NUMBER_OF_SUCH_BLOCKS
--- -------------- ---------------------
T 68 47
T 72 48
T 94 1
T 88 1
T 73 34
T 81 15
T 79 27
T 92 1
T 62 1
T 83 18
T 71 113
TB1 ROWS_PER_BLOCK NUMBER_OF_SUCH_BLOCKS
--- -------------- ---------------------
T 70 153
T 67 11
T 86 2
T 80 18
T 78 15
T 85 4
T 64 1
29 rows selected.
SQL> create table t1 as select * from dba_objects where rownum <3;
Table created.
SQL>
select 'T' tb1_name,rows_per_block,count(*)
number_of_such_blocks from (select
dbms_rowid.rowid_block_number(rowid),count(*) rows_per_block from t1
group by dbms_rowid.rowid_block_number(rowid)) group by
'T',rows_per_block
TB1 ROWS_PER_BLOCK NUMBER_OF_SUCH_BLOCKS
--- -------------- ---------------------
T 2 1
1 rows selected.
SQL> insert into t1 select * from dba_objects;
50833 rows created.
SQL> commit;
Commit complete.
SQL> create index t1_inx on t1(object_id);
Index created.
SQL> exec dbms_stats.gather_table_stats(’HR','t1',cascade=>true);
PL/SQL procedure successfully completed.
SQL> select 'T' tbl_name, rows_per_block,
count(*) number_of_such_blocks from (
2 select dbms_rowid.ROWID_BLOCK_NUMBER
( rowid ), count(*) rows_per_block
3 from t1
4 group by dbms_rowid.ROWID_BLOCK_NUMBER( rowid ))
5 group by 'T', rows_per_block;
6 /
TB ROWS_PER_BLOCK NUMBER_OF_SUCH_BLOCKS
-- -------------- ---------------------
T1 2 25297
T1表上将每个数据块上存放的记录数缩小为2条,这样T1表上有数据的数据块数量要远远多于T表。
SQL> set autotrace traceonly
SQL> select * from t where object_id<1000
953 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 470836197
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 954 | 88722 | 25 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T | 954 | 88722 | 25 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | T_IDX | 954 | | 4 (0)| 00:00:01 |
-------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OBJECT_ID"<1000)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
143 consistent gets
0 physical reads
0 redo size
91547 bytes sent via SQL*Net to client
1078 bytes received via SQL*Net from client
65 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
953 rows processed
SQL> select * from t1 where object_id<1000
955 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1311207630
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 956 | 88908 | 740 (1)| 00:00:09 |
| 1 | TABLE ACCESS BY INDEX ROWID| T1 | 956 | 88908 | 740 (1)| 00:00:09 |
|* 2 | INDEX RANGE SCAN | T1_INX | 956 | | 4 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OBJECT_ID"<1000)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
620 consistent gets
238 physical reads
0 redo size
91701 bytes sent via SQL*Net to client
1078 bytes received via SQL*Net from client
65 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
955 rows processed
当我们分别从T,T1表中选出1000条数据时,可以看到两个表的执行计划是相同的,返回的结果集是相同的,但T1表的一致性读的数量是620,要 比T表143大出很多,原因就是T1表中的行分布在更多的数据块上,导致Oracle需要读取更多的数据块来完成查询。从另一个角度看,我们把数据分布到 了更多的数据块上,大大降低了一个数据块被重复读取的概率。
但是这种方式的缺点是显而易见的,就是降低了数据的性能,在这种情况下,访问相同的数据意味着需要读取更多的数据块,性能会有所降低。
不过如果存在这样的情况,比如很多用户只修改1条记录并且各自更新的数据不同,那么这样做的好处就非常明显。在T表中,一个数据块上大约有70条记录,就是说很可能70个用户会同时访问一个数据块,这必然导致热块的出现;当我们让每个数据块只存放2条记录时,最多只会有2个用户会同时访问一个数据
块,这样热块的概率将会被极大地降低。
除了这种方法外我们还可以从data buffer中着手解决,主要思路为划分缓存池和提高SQL命中率。在DATA BUFFER中有如下3种pool
KEEP
pool
缓冲池将一直保留存储在其中的方案对象的数据,维护一个适当尺寸的KEEP缓冲池可以使Oracle在内存中保留数据库对象而避免I/O操作。在表、聚集、实体化视图或实体化视图日志上,KEEP子句的优先权大于NOCACHE子句
,需要显示指定。
Keep Buffer Pool的说明
KeepBuffer Pool 的作用是缓存那些需要经常查询的对象但又容易被默认缓冲区置换出去的对象,按惯例,Keep pool设置为合理的大小,以使其中存储的对象不再age out,也就是查询这个对象的操作不会引起磁盘IO操作,可以极大地提高查询性能。
注意一点,不是设置了keep pool 之后,热点表就一定能够缓存在 keep pool ,keep pool 同样也是由LRU
链表管理的,当keep pool不够的时候,最先缓存到 keep pool的对象会被挤出,不过与default pool 中的LRU的管理方式不同,在keep pool中表永远是从MRU移动到LRU,不会由于你做了FTS(全表扫描)而将表缓存到LRU端,在keep
pool中对象永远是先进先出。
在这点上对于DefaultPool就有所不同。默认情况下是nocache,即全表扫描数据在正常情况下是放到LRU的冷端,使其尽快page out(这是default pool的默认策略), 而指定了alter table
cache后,该表的全表扫描数据就不是放到LRU的冷端, 而是放到热端(MRU)了,从而使该得数据老化较慢,即保留的时间长。
因为这个原因,如果keep pool空间比table
小,导致不能完全把table keep下,那么在keep pool
中最早使用的数据还是有可能被清洗出去的。还是会产生大量的逻辑读,这样就起不到作用,所以,如果采用keep,就必须全部keep下,要么就不用keep。
综上所述,我们可以总结为:KeepPool改变的是存储位置,Cache改变的是存储方式,Cache则可以认为是无法使用keep的情况下的折中选择。
注意:如果采用Keep Pool,Data 都会cache到内存中,所以会忽略对象本身的Cache 和Nocache。
在Oracle 10g中SGA自动管理,ORACLE并不会管理keep pool,ORACLE只会管理default pool。
默认的情况下db_keep_cache_size=0,未启用,如果想要启用,需要手工设置db_keep_cache_size的值,设置了这个值之后 db_cache_size 会减少。
将表keep到内存中的过程如下
SQL> select * from v$sgainfo;
NAME BYTES RESIZEABL
------------------------- ---------- ---------
Fixed SGA Size 1218992 No
Redo Buffers 2973696 No
Buffer Cache Size 197132288 Yes
Shared Pool Size 75497472 Yes
Large Pool Size 4194304 Yes
Java Pool Size 4194304 Yes
Streams Pool Size 0 Yes
Granule Size 4194304 No
Maximum SGA Size 285212672 No
Startup overhead in Share 37748736 No
d Pool
NAME BYTES RESIZEABL
------------------------- ---------- ---------
Free SGA Memory Available 0
11 rows selected.
SQL> SELECT x.ksppinm NAME,y.ksppstvl VALUE,
x.ksppdesc describ FROM SYS.x$ksppi x, SYS.x$ksppcv y WHERE x.indx =
y.indx AND x.ksppinm LIKE '%db_cache_size%'
NAME VALUE DESCRIB
------------------------- -------------------- -----------------------------------------------------------------
__db_cache_size 197132288 Actual size of DEFAULT buffer pool for standard block size buffer
s
db_cache_size 0 Size of DEFAULT buffer pool for standard block size buffers
SQL> alter system set db_keep_cache_size=50m;
System altered.
查看
db_keep_cache_size和db_cache_size的大小
,可以看到db_cache_size变小了
SQL> show parameter db_keep_cache_size
NAME TYPE VALUE
------------------------------------ --------------------------------- ------------------------------
db_keep_cache_size big integer 52M
SQL> SELECT x.ksppinm NAME,y.ksppstvl VALUE, x.ksppdesc describ FROM
SYS.x$ksppi x, SYS.x$ksppcv y WHERE x.indx = y.indx AND x.ksppinm LIKE
'%__db_cache_size%'
NAME VALUE DESCRIB
------------------------- -------------------- -----------------------------------------------------------------
__db_cache_size 142606336 Actual size of DEFAULT buffer pool for standard block size buffer
s
将表keep到keep pool中
SQL> create table t1_keep as select rownum id,object_name from dba_objects;
Table created.
SQL> alter table t1_keep storage(buffer_pool keep);
Table altered.
SQL> create table t2 storage(buffer_pool keep) as select rownum id,object_name from dba_objects;
Table created.
取消keep
SQL> alter table t2 storage(buffer_pool default);
Table altered.
启用cache
SQL> alter table t2 cache;
Table altered.
关闭cache
SQL> alter table t2 nocache;
Table altered.
RECYCLE
pool
缓冲池将随时清除存储在其中不再被用户需要的数据
,一个适当尺寸的RECYCLE缓冲池可以减少默认缓冲池为RECYCLE缓冲池的数据库对象的数量,以避免它们占用不必要的缓冲空间
,需要显示指定。设置表使用
RECYCLE
pool
SQL> alter table t2 storage(buffer_pool recycle);
Table altered.
DEFAULT
pool
缓冲池中存储的是没有被指定使用其他缓冲池的方案对象的数据,以及被显式地指定使用DEFAULT缓冲池的方案对象的数据。
实际生产环境下,我们可以将被访问次数较多的热块,存放在keep pool中;将被访问次数较较少的冷块,存放在recycle pool中;将被访问次数一般,则保持default pool不变
注意:上述三种数据缓冲池只有标准容量的数据缓存区才具备。非标准容量数据块使用的数据缓冲区中只有 DEFAULT 缓冲池。
关于提高buffer cache提高缓存命中率实际上最有效的办法,是从优化sql入手,不良的sql往往带来大量的不必要的访问,这是造成热点块的根源。比如本该通过全表扫描的查询却走了索引的range scan,这样将带来大量的对块的重复访问。从而形成热点问题。再或者比如不当地走了nested loops的表连接,也可能对非驱动表造成大量的重复访问。那么在这个时候,我们的目标就是找出这些sql来并尝试优化。关于如何找出造成热块的sql可参考
http://czmmiao.iteye.com/blog/1292412
最直接的就是扩大db_cache_size。在10g以后,oracle建议采用sga的自动内存管理,但是我们可以为我们data buffer设置最小值。
SQL> alter system set db_cache_size=100M;
System altered.
设置data buffer的最小值为100MB。
索引数据块
这样的情况通常发生在一个RAC架构里,某个表的索引键值呈现出典型的"右倾"现象,比如一个表的主键使用一个序列来生成键值,那么这个主键在索引数据块上的键值就是以一种顺序递增的方式排列的,比如1,2,3,4,5,…,由于这些键值分布得非常接近,当许多用户在RAC的不同实例来向表中插入主键时,就会出现相同的索引数据块在不同实例的内存中被调用,形成一种数据块的争用,对于这样的情况,使用反向索引可以缓解这种争用。反向索引是将从前的索引键值按照反向的方式排列,在正常的主键B-TREE索引中,键值会按照大小顺序的排列,比如这样:
1234、1235、1236、1237
而反向索引之后,键值变成下面的样子:
4321、5321、6321、7321
这样,本来是放在相同的索引数据块上的键值,现在分布到不同的数据块上,这样用户在RAC不同的实例上插入的主键值因为分布在不同的数据块上,所以不会导致热块的产生,这基本上是反向索引被使用的唯一情况。
反向索引使用场合之所以如此受限,是因为它丢弃了B-TREE索引的一个最重要的功能:
INDEX RANGE SCAN
索引访问方式中,这个方式最为常见,但是反向索引却不能使用这个功能,究其原因就是,反向索引已经把键值的排列顺序打乱,当按照键值顺序地查找一个范围时,在反向索引中,由于键值被反向存储,这些值已经不是连续存放的了。所以INDEX RANGE SCAN的方式在反向索引中没有任何意义。看下面的例子:
SQL> set autotrace trace explain
SQL> select * from t where id > 1234 and id < 1999;
Execution Plan
----------------------------------------------------------
Plan hash value: 2152055767
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 765 | 3060 | 3 (0)| 00:00:01 |
|* 1 | INDEX RANGE SCAN| T_INX | 765 | 3060 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("ID">1234 AND "ID"<1999)
SQL> select * from t1 where id > 1234 and id < 1999;
Execution Plan
----------------------------------------------------------
Plan hash value: 3617692013
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 765 | 3060 | 22 (10)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T1 | 765 | 3060 | 22 (10)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("ID"<1999 AND "ID">1234)
SQL> select /*+ index(t1,t1_inx) */* from t1 where id > 1234 and id < 1999;
Execution Plan
----------------------------------------------------------
Plan hash value: 3995001570
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 765 | 3060 | 114 (2)| 00:00:02 |
|* 1 | INDEX FULL SCAN | T1_INX | 765 | 3060 | 114 (2)| 00:00:02 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("ID"<1999 AND "ID">1234)
我们看到,对于一个在实际应用中非常常见的条件范围的查询,在反向索引中却只能够通过全表扫描或者全索引扫描的方式来实现,这就是反向索引的一个非常严重的缺陷,所以在生产环境下使用它时要十分慎重。
索引根数据块
热块也可能发生在索引的根数据块上。我们知道在B-TREE索引里,当Oracle访问一个索引键值时,首选访问索引的根,然后是索引的分支,最后才是索引的叶块,索引的键值就是存储在叶块上面,下图是B-TREE索引示意图。
当索引的根、枝数据都集中在几个数据块上时,比如D,G所在的枝数据块,当用户访问的范围从A~L时,都会访问这个数据块,如果很多用户频繁地访问这个范围的索引键值,有可能导致这个枝数据块变成热块。
当出现这种现象时,可以考虑对索引做分区,以便于使这些根、枝数据块分布到不同的数据段(分区)上,减少数据块的并行访问的密度。请看下面例子
SQL> create table t(id number(10),object_name varchar2(50))
2 partition by range(id)(
3 partition t_range_p1 values less than(10) tablespace example,
4 partition t_range_p2 values less than(100) tablespace example,
5 partition t_range_p3 values less than(200) tablespace example,
6 partition t_range_p4 values less than(300) tablespace example,
7 partition t_range_p5 values less than(500) tablespace example,
8 partition t_range_p6 values less than(600) tablespace example,
9 partition t_range_p7 values less than(700) tablespace example,
10 partition t_range_p8 values less than(800) tablespace example,
11 partition t_range_p9 values less than(900) tablespace example,
12 partition t_range_p10 values less than(1000) tablespace example,
13 partition t_range_p11 values less than(1100) tablespace example,
14 partition t_range_p12 values less than(1200) tablespace example,
15* partition t_range_max values less than(maxvalue) tablespace example)
Table created
SQL> insert into t
2 select rownum id,object_name from dba_objects;
50333 rows created.
SQL> commit;
Commit complete.
SQL> create index t_inx on t(id) local;
Index created.
SQL> exec dbms_stats.gather_table_stats('HR','T',cascade=>true);
PL/SQL procedure successfully completed.
SQL> create table t1 as select rownum id,object_name from dba_objects;
Table created.
SQL> create index t1_inx on t1(id);
Index created.
SQL> exec dbms_stats.gather_table_stats('HR','T1',cascade=>true);
PL/SQL procedure successfully completed.
SQL> alter session set sql_trace=true;
Session altered.
SQL> select /*+ index(t t_inx) */ * from t where id<1000;
.....................
999 rows selected.
SQL> select /*+ index(t1 t1_inx) */ * from t1 where id<1000;
.....................
999 rows selected.
SQL> alter session set sql_trace=false;
Session altered.
trace文件中的t表执行计划如下
select /*+ index(t t_inx) */ *
from
t where id<1000
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 2 0.00 0.00 0 0 0 0
Execute 2 0.00 0.00 0 0 0 0
Fetch 136 0.02 0.02 0 308 0 1998
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 140 0.02 0.02 0 308 0 1998
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 55
Rows Row Source Operation
------- ---------------------------------------------------
999 PARTITION RANGE ITERATOR PARTITION: 1 10 (cr=154 pr=0 pw=0 time=38191 us)
999 TABLE ACCESS BY LOCAL INDEX ROWID T PARTITION: 1 10 (cr=154 pr=0 pw=0 time=27015 us)
999 INDEX RANGE SCAN T_INX PARTITION: 1 10 (cr=77 pr=0 pw=0 time=10564 us)(object id 52535)
trace文件中的t1表执行计划如下
select /*+ index(t1 t1_inx) */ *
from
t1 where id<1000
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 68 0.03 0.02 0 141 0 999
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 70 0.03 0.02 0 141 0 999
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 55
Rows Row Source Operation
------- ---------------------------------------------------
999 TABLE ACCESS BY INDEX ROWID T1 (cr=141 pr=0 pw=0 time=166354 us)
999 INDEX RANGE SCAN T1_INX (cr=71 pr=0 pw=0 time=51109 us)(object id 52550)
从结果中可以看到,T1表上的SQL扫过了71个索引数据块,而T表扫过了77个索引块,T表索引的访问方式为分区索引的范围扫描。尽管两个SQL扫过相同的索引键值,但是T表却比T1表多扫过13+6=19个数据块,原因就是T的索引分布在不同的分区上,Oracle需要多次通过索引根数据块才能访问 到键值,所以就会多出一些数据块来。
上面的例子说明了当把一个索引创建为分区索引时,需要将索引的根数据块会分布到更多的数据块上,具体可通过控制pctfree参数来实现。通过这种方式,可以避免由于索引根、枝数据块太集中导致热块产生。
段头数据块
在Oracle 9i之前,数据块的空间使用情况需要手工来管理,在每个数据段的段头有个(或者几个)Free List列表,用于存放段中哪些数据块可以使用。当数据块里面的数据达到数据块总容量的一个比例时,数据块就会从Free List列表中剔除,这个数据块就不能够再插入数据。这个比例由参数PCT_FREE来确定。当数据块的空间减少到一个比例时,数据块就会被放到Free List列表中,这些数据块可以被用来插入数据。这个比例由参数PCT_USED确定。
在OLTP系统数据库中,一些数据段的Free List可能会是一个访问很频繁的数据块,比如这个数据库上有些表有很多删除、插入的动作,很多会话需要不断访问这些数据块的Free List列表,以便获得需要的数据块信息。此时这个数据块(称作段头数据块)就会变成一个热块,此时内存中就会出现比如cache buffer chain这样的Latch等待事件;当出现这个问题时,一个常见的解决方法是增加Free List的数量,以便于分散会话访问数据块的密度,比如有10个用户并行地向一个表中插入数据,我们设置Free Lists的值为10,就可以避免出现等待,这在一定程度上能够缓解段头的热块问题。
从Oracle 9i开始,引入了一个自动段管理的技术ASSM(Automatic Segment Space Management,ASSM),它让Oracle自动管理"Free Lists"。实际上在ASSM里面,已经没有Free List这样的列表结构,Oracle使用位图方式来标记数据块是否可用,这种数据块的空间管理方式比用一个列表来管理更加高效。当然段头位图端也有可能出现等待,如果等待集中在
BMB
上,那么一般来说只能通过使用分区表或者调整应用等手段来解决了。
对于一个OLTP系统,表的DML操作非常密集,对于这些表,使用ASSM方式来管理会比人工管理更加方便和准确,能有效地避免段头变成热块;而对于OLAP系统数据库,这个参数并没有太大的实际意义,因为在这样的数据库中,很少有表发生频繁修改,OLAP系统数据库主要的工作是报表和海量数据的批量加载。
数据块自身的争用
HASH
分区表和HASH
簇表
是解决热块冲突的一种较为常用的办法,对于表数据量较大的情况,可以考虑采用
HASH
分区表。比如有一张表,主键是通过
SEQUENCE
产生的,那么在没有使用
HASH
分区表的情况下,同一个时间点产生的记录存储在同一个数据块中的可能性很大。而这些数据随后又被其他应用使用,这样产生热块的机会就很高了。如果我们将这张表根据主键设计成
HASH
分区表,那么同一个时刻产生的记录就被
HASH
算法分布到不同的表分区中去了,访问这些数据的时候就可以从多个数据块中读取,从而缓解了热块冲突。
任何事物都有两面性,
HASH
分区也是。
HASH
分区
表解决了热块冲突的问题,但是带来了另外一个问题,如果我们的应用总是通过主键来访问这张表的数据,那么这种方式确实是最好的。但是如果我们还有大量的应用需要根据主键进行范围扫描,或者按照记录的生成日期进行范围扫描,那么
HASH
分区表的弱点就显现出来了。原本放在同一个数据块中的数据被
HASH
算法分散开了,这同时意味着我们对这些数据做范围扫描的时候需要扫描更多的数据块。这就是
HASH
分区表的弱点,增加了范围扫描的成本。
在实际的生产环境中,我们可能不总是那么幸运,我们肯定会碰到两方面的需求。一方面是热块冲突必须解决,另外一方面可能我们还存在一定的应用要对这些数据做范围扫描。在这种情况下,我们必须进行综合的评估,到底哪种需求是主要需求。如果我们优化范围扫描对系统更为有利,那么我们就必须放弃
HASH
分区;如果解决热块冲突更为重要,那么我们就必须牺牲范围扫描。
参考至:《让Oracle跑得更快》谭怀远著
http://blog.sina.com.cn/s/blog_7414f6640100uouf.html
http://www.oraclefans.cn/forum/showblog.jsp?rootid=17841
http://www.ordba.net/Tutorials/Seg4.htm
http://justdba.blogbus.com/logs/65743832.html
http://blog.csdn.net/tianlesoftware/article/details/6581159
本文原创,转载请注明出处、作者
如有错误,欢迎指正
邮箱:czmcj@163.com
发表评论
-
Oracle Redo 并行机制
2017-04-07 11:31 986Redo log 是用于恢复和一个高级特性的重要数据,一个r ... -
Append Values and how not to break the database
2015-09-29 20:12 745With the advent of the /*+ APP ... -
基于案例学习sql优化第6周脚本
2015-04-13 04:29 0===============BEGIN=========== ... -
Oracle表高水平位的优化与监控
2015-02-13 09:21 2223高水平位虚高的案例 --构造表drop table t p ... -
Oracle行迁移和行链接详解(原创)
2015-02-13 09:00 12177行迁移成 因:当发出u ... -
Parse CPU to Parse Elapsd%的理解
2015-01-19 13:59 1440Parse CPU to Parse Elapsd%是指sq ... -
ALTER INDEX COALESCE: 10g Improvements
2014-08-02 21:34 931I thought it might be worth me ... -
Differences and Similarities Between Index Coalesce and Shrink Space
2014-08-02 21:21 957As already discussed, ALTER IN ... -
Alter index coalesce VS shrink space
2014-08-02 17:56 102010g中引入了对索引的shrink功能,索引shrink操 ... -
SQL Plan Management Creating SQL plan baselines(原创)
2014-08-01 23:56 1362SQL Plan Management SQL Plan ... -
WITH Clause : Subquery Factoring
2014-07-23 08:43 1186Subquery Factoring The WIT ... -
Query Transformations : Subquery unnesting(原创)
2014-07-23 08:42 2907Subquery Unnesting Subqueries ... -
Automating Parallelism
2014-07-17 17:49 837Parallel query, the essence of ... -
Parallel Execution: Large/Shared Pool and ORA-4031 (文档 ID 238680.1)
2014-07-17 17:47 2100Applies toOracle Database - En ... -
Optimizer Transformations: Star Transformation
2014-06-30 07:32 785Star transformation was intro ... -
Star Transformation And Cardinality Estimates
2014-06-30 07:33 890If you want to make use of Orac ... -
Optimizer statistics-driven direct path read decision for full table scans
2014-06-06 16:09 1079Hello all fellow Oracle geeks ... -
Cut out from Ask Tom-- Thanks for the question regarding "10053", version 9.2.6
2014-03-09 23:38 1436You AskedDear tom,A. your new ... -
ORACLE SQL TUNING各种技巧及复杂实例
2014-02-25 23:17 6516一.优化器模式ORACLE的优化器共有3种:a. RULE ... -
Oracle Predicate Pushing(原创)
2014-02-22 21:17 4626IntroductionThe join predicate ...
相关推荐
Word 出现标题显示黑色的方块终极解决方法,亲测好使!! 网上常见的治标不治本的方法: 1、将光标移至黑块的右侧,之后按键盘左方向键“←”,此时黑块变为灰色,即为“选中”状态 2、之后按下键盘组合键...
### SEO文章原创方法集合 在当今互联网竞争激烈的环境中,搜索引擎优化(SEO)成为了提升网站排名、增加流量的关键手段之一。而作为SEO的核心组成部分之一,原创文章的创作能力尤为重要。接下来,我们将详细介绍一...
这篇教程将深入探讨如何有效地挖掘和创作出具有独特价值的原创文章,挑战现有的寻找原创内容的常见方法。 首先,我们要理解什么是高质量的原创文章。高质量的文章不仅要求内容新颖、独特,还要有深度、逻辑清晰,并...
4. GHOST备份与RAR压缩的类似之处:GHOST备份与RAR压缩类似,都可以用压缩文件来备份系统,可以使用类似的方法来解决GHOST恢复过程中的错误提示问题。 5. PE环境的使用:PE环境可以用来解决GHOST恢复过程中的错误...
"WINCC中使用C脚本获得操作记录的方法" WINCC是一种工业自动化软件,能够帮助用户实时监控和控制工业过程。然而,在某些情况下,用户需要记录操作员的操作,以便进行事故分析或性能优化。这时,WINCC提供了一些对象...
Eclipse + MinGW + Qt 安装及问题解决方法 本文总结了在 Windows XP 平台下安装 Eclipse + MinGW + Qt 的步骤和解决方案,以便开发 C++ 项目。在安装过程中遇到的问题和解决方法也进行了总结。 一、下载和安装 Qt ...
- 使用`XLua.hotfix`方法对特定C#类的函数进行热修复或替换。 以上就是Unity_XLua热更新的基本流程,通过这些步骤,开发者可以在不重新发布整个游戏客户端的情况下,对游戏逻辑进行修改和更新,提升游戏的迭代速度...
因此,高质量的内容创作仍应以原创和有价值的信息为核心,适度使用伪原创技巧,以达到最佳的SEO效果。 总结来说,伪原创词库是一种辅助工具,用于帮助内容创作者改进和多样化他们的作品,以适应搜索引擎的要求。它...
用Java编写的一个打方块下游戏,游戏面板的最下面有一个挡板,上面是若干个方块,一个小球在四处弹射,球撞到方块上方块就消失并加分,球撞到墙壁上就反弹,玩家用鼠标或键盘控制下面挡板的左右移动不让小球掉入地...
下面将详细解析关于“SEO伪原创文章的12种方法”的相关内容,帮助理解和掌握这些技巧。 ### 1. 标题修改 标题是文章的门面,也是搜索引擎抓取的重要元素。通过对原文章标题进行修改,可以使其看起来更具有原创性。...
### FFMpeg解码端代码分析—宏块层面解析 #### 概述 本文将针对FFMpeg解码端的代码进行深入分析,重点聚焦于解码框架、关键流程及重要函数等方面,直至宏块层级的理解。对于视频解码领域的初学者而言,这将是一篇...
根据提供的文件信息,本文将详细解释一个原创的CRC-8计算方法,并且通过代码示例进一步阐述其实现细节。此CRC-8算法被设计为易于理解和实现,特别适用于嵌入式系统开发中需要进行数据校验的应用场景。 ### 一、CRC...
使用伪原创工具可以制作出互联网上具有唯一性的伪原创文章。 其专门针对百度和google的爬虫习惯以及分词算法而开发,通过本软件优化的文章,将更被搜索引擎所青睐. 解压后既可使用(需安装微软.NET Framework 2.0...
在"18717常用数学模型及建模方法"文档中,你可能会看到如何使用MATLAB构建和求解各种模型的具体示例,包括但不限于: - 线性规划和整数规划问题的`linprog`函数应用。 - 逻辑回归和神经网络的建模,用于分类和预测...
标题中的“PHPCMS遭遇会员投稿审核无效的解决方法”是指在使用PHPCMS内容管理系统时,遇到会员投稿后,后台无法进行文章审核的问题。这个问题可能是由于系统内部的某些错误或异常导致的,影响了正常的审核流程。 ...
《解决问题的方法与假设》是凯捷咨询在2004年推出的一份关于技术咨询的专业培训材料,旨在为咨询团队提供一套结构化的解决问题的方法论。该文档的核心目标是通过系统化的问题解决流程,帮助团队建立共同的工作模式,...
夫唯老师提出的原创文章终极方法,旨在帮助网站拥有者在保持高质量的同时,避免使用伪原创工具,从而获得更好的搜索引擎评分。 1. **寻找原始资料**: - 老师建议的策略是使用专业书籍和杂志。这些出版物往往未被...
通过上述方法,我们可以将创作真原创文章的时间与精力,转化为产出高质量、有价值的原创内容。在这个过程中,不仅提高了搜索引擎的排名,也能赢得用户的认可,建立专业和权威的形象。因此,结束伪原创,转向真原创是...
- SEO优化:搜索引擎对原创内容给予更高的排名,因此内容创作者会使用这类工具来确保他们的文章具有足够的原创性。 - 学术研究:学者在发表论文前需要确保其内容没有重复,以防止抄袭指控。 - 内容审核:新闻网站...
次文档为本人原创,欢迎大家转载,让搜索引擎能够更好的搜到有用的解决方法,让别人少走弯路!