| 维度 | Latch | Lock |
|---|---|---|
| 保护对象 | 内存结构(Buffer Cache、Library Cache 等) | 数据库对象(行、表、事务) |
| 持续时间 | 极短(纳秒/微秒级) | 较长(事务期间) |
| 等待行为 | 自旋(Spin) → 休眠(Sleep) | 直接入等待队列 |
| 死锁处理 | 无死锁检测,依赖编码规范 | 有死锁检测与解决机制 |
// 伪代码逻辑int attempts = 0;while (attempts < spin_count) { // 阶段1: 自旋
if (try_get_latch()) return; // 尝试获取
attempts++;
spin_cpu(); // 空转消耗CPU}sleep(); // 阶段2: 休眠,让出CPUlatch free 等待事件| Latch 名称 | 保护对象 | 典型高并发场景 |
|---|---|---|
cache buffers chains |
Buffer Cache 中 Hash Bucket 链表 | 热点块、全表扫描、索引分裂 |
cache buffers lru chain |
LRU 链表 | 大量物理读、DBWR 写压力 |
shared pool |
Library Cache 内存分配 | 硬解析、版本过多、共享池碎片 |
library cache |
SQL/PLSQL 执行计划 | 大量并发硬解析、授权检查 |
row cache objects |
数据字典缓存 | 序列高并发、大量 DDL |
redo copy |
Redo Log Buffer 拷贝 | 高并发 DML、小事务批量提交 |
redo allocation |
Redo Log Buffer 空间分配 | 同上 |
-- 查看 Latch 等待分布(AWR)SELECT latch_name,
gets, misses,
ROUND(misses/DECODE(gets,0,1,gets)*100, 2) miss_pct,
sleeps, spin_gets, wait_timeFROM v$latchWHERE misses > 0ORDER BY wait_time DESC;-- ASH 实时分析SELECT event, p1 latch_addr, p2 latch_num, p3 level#,
sql_id, count(*)FROM v$active_session_historyWHERE event LIKE '%latch%'GROUP BY event, p1, p2, p3, sql_idORDER BY count(*) DESC;-- 通过 latch 地址关联具体对象(cache buffers chains 为例)SELECT /*+ RULE */
e.owner ||'.'|| e.segment_name segment_name,
e.segment_type,
SUM(tch) touch_countFROM x$bh b, dba_extents eWHERE b.hladdr = '&latch_addr' -- 从等待事件 P1 获取
AND b.file# = e.file_id
AND b.dbablk BETWEEN e.block_id AND e.block_id + e.blocks - 1GROUP BY e.owner, e.segment_name, e.segment_typeORDER BY SUM(tch) DESC;-- 查找热点 Hash BucketSELECT hladdr, count(*), SUM(tch) FROM x$bh
GROUP BY hladdr
HAVING count(*) > 100 ORDER BY 3 DESC;-- 查找具体热点块SELECT obj, dbarfil, dbablk, tch
FROM x$bh
WHERE hladdr = '&hot_latch_addr';| 方法 | 适用场景 | 操作 |
|---|---|---|
| 反向索引 | 索引热块(如序列主键) |
REVERSE 关键字重建索引 |
| 分区表 | 大表全表扫描导致热块 | 将表分区,分散到不同 Hash Chain |
| 增大 DB_BLOCK_LRU_LATCHES | 11g 之前版本 | 增加 LRU Latch 数量(默认 CPU_COUNT) |
| 优化 SQL 执行计划 | 全表扫描替代索引 | 添加合适索引,减少块访问 |
| **避免 Select * ** | 宽表热点块 | 只查询必要列,减少块占用 Buffer 数 |
-- 查找高版本 SQL(Version Count)SELECT sql_id, version_count, executions,
sql_text
FROM v$sqlarea
WHERE version_count > 100 ORDER BY version_count DESC;-- 查找无效ation原因SELECT * FROM v$sql_shared_cursor WHERE sql_id = '&sql_id';-- 差:硬解析SELECT * FROM t WHERE id = 1;SELECT * FROM t WHERE id = 2;-- 优:软解析SELECT * FROM t WHERE id = :b1;ALTER SYSTEM SET cursor_sharing = 'FORCE';-- 针对特定游标exec DBMS_SHARED_POOL.PURGE('&address, &hash_value', 'C');-- 检查 shared pool 碎片化SELECT * FROM v$shared_pool_reserved;-- 增大 Redo Log BufferALTER SYSTEM SET log_buffer = 67108864; -- 64M,需重启-- 使用批量提交替代单条提交-- 差:每行提交FOR i IN 1..10000 LOOP
INSERT INTO t VALUES (i);
COMMIT; -- 产生大量 redo allocationEND LOOP;-- 优:批量提交FOR i IN 1..10000 LOOP
INSERT INTO t VALUES (i);END LOOP;COMMIT;latch free 等待极高时,需找到
谁持有 Latch 不释放:-- 查找 Latch 持有者(需快速执行,信息易失)SELECT s.sid, s.serial#, s.username, s.program,
l.name, w.holding_user, w.holding_sessionFROM v$latchholder w, v$latch l, v$session sWHERE w.latch# = l.latch#
AND w.sid = s.sid;-- 结合 Systemstate Dump(极端情况)oradebug setmypid
oradebug dump systemstate 266; -- Level 266 含 Latch 持有栈| 参数 | 默认值 | 调优建议 |
|---|---|---|
_spin_count |
2000 | 单 CPU 或 CPU 极忙时可适当降低,减少 CPU 空转 |
_latch_classes |
0 | 极少使用,Oracle 内部管理 |
db_block_lru_latches |
CPU_COUNT | 11g+ 自动调整,一般不动 |
shared_pool_size |
自动 | 硬解析严重时适当增大,但需配合绑定变量 |
Latch Free 高?
├─ cache buffers chains → 热点块 → 反向索引/分区/优化SQL
├─ library cache/shared pool → 硬解析 → 绑定变量/CURSOR_SHARING
├─ redo copy/allocation → 高并发DML → 增大log_buffer/批量提交
└─ row cache objects → 序列/DDL → 序列Cache/减少DDL
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/7655508/viewspace-3117571/ ,如需转载,请注明出处,否则将追究法律责任。