当访问频率非常高的数据块称为热块(hot block),当很多用户一起去访问某几个数据块时,就会导致一些 Latch 争用。最常见 Latch 争用是:
- buffer busy waits
- cache buffer chain
这两个 Latch 争用分别发生在访问数据块的不同时刻。
当一个会话需要去访问一个内存块时,它首先要去一个像链表的结构中去检索这个数据块是否存在在内存中,会话访问这个链表时需要获得一个 Latch,如果获得失败,就会产生 Latch cache buffer chains 等待,导致这个等待的原因是访问相同数据块的会话太多或者这个列表太长(如果读到内存中的数据块太多,需要管理数据块的 hash 列表就会很长,这样会话扫描列表的时间就会增加,持有 cache buffer chain latch 的时间就会变长,其他会话获得这个 Latch 的机会就会降低,等待就会增加)。
当一个会话需要访问一个数据块,而这个数据块正在被另一个用户从磁盘读取到内存中或者这个数据块正在被另一个会话修改时,当前会话就需要等待,就会产生一个 buffer busy waits 等待。
产生这些 Latch 争用的直接原因是太多的会话去访问相同的数据块导致热块问题,造成热块的原因可能是数据库设置导致或重复执行 SQL 频繁访问一些相同数据块导致。
热块产生的原因,按数据块类型,可以分为如下类型,不同热块类型处理的方式不同。
- 表数据块
- 索引数据块
- 索引根数据块
- 文件头数据块
本文演示表数据块。
比如在 OLTP 系统中,一些小表,会出现某些数据块被频繁查询或修改的操作,此时,这些被频繁访问数据块就会成为热块,导致内存中的 Latch 争用。
from dba_objects;
表已创建。
SQL> create index t_idx on t(object_id);
索引已创建。
SQL> exec dbms_stats.gather_table_stats('test','t',cascade=>true);
PL/SQL 过程已成功完成。
SQL> select 't' tbl_name, rows_per_block, count(*) number_of_such_blocks
2 from (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 ROWS_PER_BLOCK NUMBER_OF_SUCH_BLOCKS
- -------------- ---------------------
t 69 28
t 64 117
t 58 1
t 60 1
t 80 10
t 88 2
t 62 10
t 76 28
t 63 53
t 78 13
t 83 1
T ROWS_PER_BLOCK NUMBER_OF_SUCH_BLOCKS
- -------------- ---------------------
t 71 23
t 75 27
t 74 45
t 89 2
t 66 170
t 67 80
t 85 1
t 23 1
t 79 11
t 73 38
t 65 227
T ROWS_PER_BLOCK NUMBER_OF_SUCH_BLOCKS
- -------------- ---------------------
t 68 44
t 77 25
t 72 28
t 70 37
t 81 3
t 90 2
t 61 2
已选择29行。
SQL>