ITPub博客

首页 > Linux操作系统 > Linux操作系统 > latch free 等待事件说明(转)

latch free 等待事件说明(转)

原创 Linux操作系统 作者:tolywang 时间:2007-07-07 00:00:00 0 删除 编辑
当进程想要获取锁存器而此时该锁存器正被其他进程持有时产生Latch Free(锁存器空闲)等待事件,类似于排队,Oracle使用锁存器来保护数据结构。一次只能在一个进程在获得锁存器后修改或检查数据结构。其他需要访问该数据结构的进程必须等到它们获得锁存器后。不同于排队
的是,请求锁存器的进程不需要在队列中等待。如果获取锁存器失败,则进程仅仅等待一小段时间就可以再次请求锁存器。这一小段等待时间成为“自旋”(spin)。如果在一次或多次自旋重复(spin iterations)之后还没获取锁存器,进程就休眠一小段时间,然后再次尝试获取锁存器,
接下来休眠更长一段时间,直到获得锁存器。

最常见的锁存器有:cache buffer chains(高速缓存缓冲区链)、library cache(高速缓存)

和shared pool(共享池)。

1、等待参数



latch free的等待参数描述如下:

◎ P1 进程等待的锁存器地址。

◎ P2 锁存器号,同v$latchname.latch#

要查找等待锁存器的名称,可以是哟功能如下SQL语句:

SELECT *

FROM v$latchname

WHERE latch# = &P2_Value;

◎ P3 尝试的次数;显示进程试图获取锁存器的次数计数器。



2、等待时间

该时间的等待时间呈指数级增长。他不包含进程为锁存器自旋(spin) 花费的时间。



以不等待模式获取的锁存器在IMMEDIATE_GETS和IMMEDIATE_MISSES列中统计。

通过愿意等待模式获取锁存器在GETS和MISSES列中有统计。特殊锁存器的GETS列在每次进程

通过愿意等待模式请求该锁存器时递增。

如果锁存器不能用,那么进程会在CPU上自旋(spin)一小段时间,重新尝试该锁存器。

v$system_Event视图中的latch free等待事件的total_waits统计追踪进程以愿意等待模式

无法获得一个锁存器的次数。v$latch视图中特殊锁存器的sleeps统计追踪进程在锁存器上睡眠

的次数。因为进程在_SPIN_COUNT次数后无法获得锁存器时没有别的事可做只好睡眠,total_times

应该等于sleeps的综合,然而,很多时候total_times大于sleeps的总合。这是因为sleeps统计

只有在锁存器GET操作成功才更新,而不是每次尝试是更新。

因为latch free等待事件总是很短,所以可以看到total_waits的一个较大的数字,这是计

数器在一段短时间内发生的等待事件。



3、常见原因、诊断和动作

锁存器征用表名另一个进程持有该锁存器过长的时间。当结合高需求量,这种争用带

来的影响将会扩大,从而明显地降低性能。锁存器争用在高度并发的环境中很普遍。可以

根据如下SQL查看进程竞争的热锁存器:

SELECT NAME,

Gets,

Misses,

Immediate_Gets,

Immediate_Misses,

Sleeps

FROM V$latch

ORDER BY Sleeps;



◎ shared pool锁存器和library cache锁存器的争用——解析

shared pool锁存器和library cache锁存器的争用主要是由于紧密的硬解析。过多

的硬解析通常出现在主要使用带有字面值的SQL语句的应用程序中。应解析是代价

昂贵的才做,并且在解析期间必须持有子library cache锁存器。



①.使用下面语句查数据库中硬解析的数量:

SELECT a.*,

SYSDATE - b.Startup_Time Days_Old

FROM V$sysstat a,

V$instance b

WHERE a.NAME LIKE 'parse%';

②.发现执行许多硬解析的当前会话:

SELECT a.Sid,

c.Username,

b.NAME,

a.VALUE,

Round((SYSDATE - c.Logon_Time) * 24) Hours_Connected

FROM V$sesstat a,

V$statname b,

V$session c

WHERE c.Sid = a.Sid

AND a.Statistic# = b.Statistic#

AND a.VALUE > 0

AND b.NAME = 'parse count (hard)'

ORDER BY a.VALUE;

③.标识作为绑定变量的合适候选的literal SQL语句:

SELECT Hash_Value,

Substr(Sql_Text, 1, 80)

FROM V$sqlarea

WHERE Substr(Sql_Text, 1, 40) IN

(SELECT Substr(Sql_Text, 1, 40)

FROM V$sqlarea

HAVING COUNT(*) > 4

GROUP BY Substr(Sql_Text, 1, 40))

ORDER BY Sql_Text;

④.正确的设置SESSION_CACHED_CURSOES参数:

每当SQL语句到达时,Oracle检查该语句是否已经在库高速缓存中。如果是的话,

只需要很少的开销就可以执行该语句;这种进程被称为软解析。在硬解吸不行时,软

解析也不好。library cache锁存器在软解析中获得。Oracle仍然必须检查语句的语法

和语义,除非该语句高速缓存在会话的游标高速缓存中。通过正确的设置

SESSION_CACHED_CURSOES参数,可以减少library cache锁存器持有时间。然而最好的

方法是减少软解析的数量,这只可通过应用程序完成。

通过在v$sqlarea视图中查找带有大量parse_calls的语句,你可以找到令人不

愉快的语句。

如果发现数据库具有长共享池空闲列表,并且应用程序使用literal SQL,那么就

应该考虑减少SHARED_POOL_SIZE。这将减少share pool锁存器的争用。

也应该使用dbms_shared_pool.keep过程钉住共享池中可重用的对象。

v$db_object_cache视图具有保存相关对象的信息。



◎ library cache锁存器的争用——带有高版本数的语句

Oracle使用多个子游标来区分一些SQL语句,这些SQL语句具有相同的字符,但是不能

被共享,因为他们引用不同的底层对象。例如:如果数据库有三个Customer表,并且

每个表属于不同的模式,那么每个拥有者发布的SELECT * FROM Customer语句将具有

相同的散列值,但是具有不同的子段数量。当被解析语句散列值匹配带有高的子段数

或版本数的语句散列值时,Oracle必须比较语句和所有的现有版本。必须在检查期间

持续持有library cache锁存器,着可能造成其他进程无法实现他们的library cache

锁存器请求。通过在数据库中使用唯一的对象名,可以最小化这个问题。

查询列出v$sqlarea中版本数大于20的所有SQL语句:

SELECT Version_Count,

Sql_Text

FROM V$sqlarea

WHERE Version_Count > 20

ORDER BY Version_Count,

Hash_Value;



◎ cache buffer chains锁存器

在将数据读入SGA时,他们的缓冲区头被防止在悬挂散列存储桶的链表中(散列链)。

这种内存结构由大量子cache buffers chains锁存器(也称散列锁存器或CBC锁存器)

保护。希望在添加、删除、搜索、检查、读取、或修改块的进程必须首先获得cache

buffers chains锁存器,从而保护链上的缓冲区。这样就可以保证独占访问,并防

止其它进程接下来读取或改变同一个链。为了完整性牺牲了并发性。通过设置

_DB_BLOCK_HASH_LATCHS参数可以调整散列锁存器数量。

如下SQL取实例中散列锁存器的数量:

SELECT COUNT(DISTINCT(Hladdr)) FROM X$bh;



①.cache buffers chains锁存器的争用——底效率的SQL语句

低效率的SQL语句是cache buffers chains锁存器争用的主要原因。当和高并发

率混合在一起时,花费在latch free等待事件上的时间可能更多。在某些环境中,

应用程序打开执行相同的低效率SQL语句的多个并发会话,并且这些SQL语句都没法得

到相同的数据集,这种情况下相当普遍。

如果集注下面3个方面,你可以做的很好:

◆ 每个逻辑读取需要一个latch gey操作和一个CPU

◆ 从latch get例程中获得的唯一方法是获得锁存器

◆ 在任意时刻,只有一个进程可以拥有cache buffer链,并且这个锁存器覆盖

许多数据块,另一个进程可能需要其中一些数据块。



②.cache buffers chains锁存器的争用——热块

热块(hot block)是cache buffer chains锁存器争用的另一个常见原因。当多个

会话重复访问一个或多个由同一个子chche buffer chains锁存器保护的块时,热块

就产生。这主要是一种应用程序问题。在大多数情况下,增加cache buffer chains

锁存器的数量对性能的改变没多大帮助。这是因为块被散列为散列存储桶和基于块地

址和散列存储桶数量的链,而不是基于cache buffer chains锁存器的数量。如果块

地址和散列存储桶的数量保持不变,则可能有少数热块仍然被一个cache buffer chains

锁存器覆盖,除非锁存器数量极大的增加。

捕获参与争用的SQL语句:

-- Using the P1RAW from the above example (00000400837D7800).

SELECT a.Hladdr,

a.File#,

a.Dbablk,

a.Tch,

a.Obj,

b.Object_Name

FROM X$bh a,

Dba_Objects b

WHERE (a.Obj = b.Object_Id OR a.Obj = b.Data_Object_Id)

AND a.Hladdr = '&P1RAW_Value'

UNION

SELECT Hladdr,

File#,

Dbablk,

Tch,

Obj,

NULL

FROM X$bh

WHERE Obj IN

(SELECT Obj

FROM X$bh

WHERE Hladdr = '&P1RAW_Value'

MINUS

SELECT Object_Id

FROM Dba_Objects

MINUS

SELECT Data_Object_Id FROM Dba_Objects)

AND Hladdr = '&P1RAW_Value'

ORDER BY 4;



展开块的方法:

◆ 通过ROWID删除并且重新插入一些行

◆ 输出表,较大的增加PCTFREE,并且输入数据。这可以最小化每个块的行数量,

将他们展开到多个块上。当然这是以存储空间作为代价,并且全表扫描会更慢。

◆ 最小化表中每个块的记录数量。这涉及转储少量数据块,用于获得每个块的当

前理想行数。手工插入你确定合适的行数,然后发布命令:

ALTER TABLE table_name MINIMIZE RECORED_PER_BLOCK。截取表和输入数据。

◆ 对于索引,对于较高的PCTFREE值可以重建他们,需要注意的是这种方法可能

增加索引的高度。

◆ 考虑见效块大小。这将对全表扫描带来极大的负面影响。



③.cache buffers chains锁存器的争用——长散列链

多个数据块可能被散列到同一个散列存储桶,他们和指针一起被连接到属于这个

散列存储桶的散列链上。对于大型数据库,散列链上块的数量可以达到数百个。进程

不得不顺序的扫描散列以获得所需的块,同时持有cache buffers chains锁存器不变。

我们称之为“追赶链”。当扫描长链时,锁存器必须被持有更厂的时间,并且可能造

成另一个进程无法实现她的cache buffers chains锁存器请求。

一直到Oracle 8.0,我们可以很容易地确定特定的散列链长度,因为散列锁存器、

散列存储桶和散列链之间的关系是1:1:1,散列链的长度等于有锁存器保护块的数量。

下面查寻报告每个散列上块的数量,带有10个或更多块的链为长链。

SELECT Hladdr,

COUNT(*)

FROM X$bh

GROUP BY Hladdr

ORDER BY 2;

通过使用_DB_BLOCK_HASH_BUSH_BUCKETS参数增加散列存储桶的数量,可以减少散

列的长度:

_DB_BLOCK_HASH_BUCKETS = 128021

_DB_BLOCK_HASH_LATCHES = 1024

Ratio = 128021 / 1024 = 125

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/35489/viewspace-84741/,如需转载,请注明出处,否则将追究法律责任。

上一篇: iostat 输出解析
请登录后发表评论 登录
全部评论
Oracle , MySQL, SAP IQ, SAP HANA, PostgreSQL, Tableau 技术讨论,希望在这里一起分享知识,讨论技术,畅谈人生 。

注册时间:2007-12-10

  • 博文量
    5595
  • 访问量
    13202128