演示共享池中的 Latch 争用

本文内容

  • Latch 和等待
  • 共享池中的 Latch 争用

Latch 和等待


    假设,一个数据块正在被一个会话从磁盘中读如到内存中,请注意,是正在读取中,此时,如果另外一个会话也正需要这个数据块,他该怎么办?

    此时,丈等待这个数据块被读取到内存中,这样就可以只有一个数据块在内存中,不会导致数据的不一致性。那么,正在读取数据块的会话如何能阻止别的会话继续读取这个数据块呢?方法是它需要获得一种像锁一样的资源,以便阻止其他的会话来做相同的事情,这种资源就叫 Latch。Latch 是 Oracle 为了保护内存结构而产生。

    Latch 不会造成阻塞,只会导致等待。导致 Latch 争用而等待的原因很多,内存中很多资源都可能存在争用。最常见的两类 Latch 争用:

  • 共享池中的 Latch 争用
  • 数据缓冲池中的 Latch 争用

共享池中的 Latch 争用

创建测试环境

    用 sys 用户登录,查看 Latch 争用情况:
SQL> select * from v$latchname where name like 'library cache%';
 
    LATCH# NAME                                                     HASH
---------- -------------------------------------------------- ----------
       278 library cache load lock                            2952162927
 
SQL>

    在分析系统性能是,如果看到 library cache 这样的 Latch 争用,就可以断定是共享池中出现了问题,这基本上是有 SQL 语句导致的,比如没有绑定变量或一些存储过程被反复分析。

    下面是来自 asktom.oracle.com 上给出的一个在有绑定变量和无绑定变量的情况下,Latch 资源争用的对比测试。该测试被很多 Oracle 书籍引用。测试让一条 SQL 语句执行1万次,然后给出各自的执行过程中产生的资源使用情况。

    用 sys 用户新建用户 test 并授权。

SQL> create user test identified by test default tablespace users;
 
用户已创建。
 
SQL> grant dba to test;
 
授权成功。
 
SQL> grant select on sys.v_$statname to test;
 
授权成功。
 
SQL> grant select on sys.v_$mystat to test;
 
授权成功。
 
SQL> grant select on sys.v_$latch to test;
 
授权成功。
 
SQL> grant select on sys.v_$timer to test;
 
授权成功。
 
SQL>
 
已新建用户登录。

    用 test 用户登录,执行如下操作:

SQL> conn test/test
已连接。
SQL> CREATE GLOBAL TEMPORARY TABLE run_stats
  2  (
  3     runid   VARCHAR2 (15),
  4     name    VARCHAR2 (80),
  5     VALUE   INT
  6  )
  7  ON COMMIT PRESERVE ROWS;
 
表已创建。
 
SQL> CREATE OR REPLACE VIEW stats
  2  AS
  3     SELECT 'STAT...' || a.name name, b.VALUE
  4       FROM SYS.v_$statname a, SYS.v_$mystat b
  5      WHERE a.statistic# = b.statistic#
  6     UNION ALL
  7     SELECT 'LATCH.' || name, gets FROM SYS.v_$latch
  8     UNION ALL
  9     SELECT 'STAT...Elapsed Time', hsecs FROM SYS.v_$timer;
 
视图已创建。
 
SQL> CREATE OR REPLACE PACKAGE runstats_pkg
  2  AS
  3     PROCEDURE rs_start;
  4
  5     PROCEDURE rs_middle;
  6
  7     PROCEDURE rs_stop (p_difference_threshold IN NUMBER DEFAULT 0);
  8  END;
  9  /
 
程序包已创建。
 
SQL> CREATE OR REPLACE PACKAGE BODY runstats_pkg
  2  AS
  3     g_start   NUMBER;
  4     g_run1    NUMBER;
  5     g_run2    NUMBER;
  6
  7     PROCEDURE rs_start
  8     IS
  9     BEGIN
 10        DELETE FROM run_stats;
 11
 12        INSERT INTO run_stats
 13           SELECT 'before', stats.* FROM stats;
 14
 15        g_start := DBMS_UTILITY.get_cpu_time;
 16     END;
 17
 18     PROCEDURE rs_middle
 19     IS
 20     BEGIN
 21        g_run1 := (DBMS_UTILITY.get_cpu_time - g_start);
 22
 23        INSERT INTO run_stats
 24           SELECT 'after 1', stats.* FROM stats;
 25
 26        g_start := DBMS_UTILITY.get_cpu_time;
 27     END;
 28
 29     PROCEDURE rs_stop (p_difference_threshold IN NUMBER DEFAULT 0)
 30     IS
 31     BEGIN
 32        g_run2 := (DBMS_UTILITY.get_cpu_time - g_start);
 33
 34        DBMS_OUTPUT.put_line ('Run1 ran in ' || g_run1 || ' cpu hsecs');
 35        DBMS_OUTPUT.put_line ('Run2 ran in ' || g_run2 || ' cpu hsecs');
 36
 37        IF (g_run2 <> 0)
 38        THEN
 39           DBMS_OUTPUT.put_line (
 40                 'run 1 ran in '
 41              || ROUND (g_run1 / g_run2 * 100, 2)
 42              || '% of the time');
 43        END IF;
 44
 45        DBMS_OUTPUT.put_line (CHR (9));
 46
 47        INSERT INTO run_stats
 48           SELECT 'after 2', stats.* FROM stats;
 49
 50        DBMS_OUTPUT.put_line (
 51              RPAD ('Name', 30)
 52           || LPAD ('Run1', 12)
 53           || LPAD ('Run2', 12)
 54           || LPAD ('Diff', 12));
 55
 56        FOR x
 57           IN (  SELECT    RPAD (a.name, 30)
 58                        || TO_CHAR (b.VALUE - a.VALUE, '999,999,999')
 59                        || TO_CHAR (c.VALUE - b.VALUE, '999,999,999')
 60                        || TO_CHAR (
 61                              ( (c.VALUE - b.VALUE) - (b.VALUE - a.VALUE)),
 62                              '999,999,999')
 63                           data
 64                   FROM run_stats a, run_stats b, run_stats c
 65                  WHERE     a.name = b.name
 66                        AND b.name = c.name
 67                        AND a.runid = 'before'
 68                        AND b.runid = 'after 1'
 69                        AND c.runid = 'after 2'
 70                        AND ABS ( (c.VALUE - b.VALUE) - (b.VALUE - a.VALUE))
>
 71                               p_difference_threshold
 72               ORDER BY ABS ( (c.VALUE - b.VALUE) - (b.VALUE - a.VALUE)))
 73        LOOP
 74           DBMS_OUTPUT.put_line (x.data);
 75        END LOOP;
 76
 77        DBMS_OUTPUT.put_line (CHR (9));
 78        DBMS_OUTPUT.put_line (
 79           'Run1 latches total versus runs -- difference and pct');
 80        DBMS_OUTPUT.put_line (
 81              LPAD ('Run1', 12)
 82           || LPAD ('Run2', 12)
 83           || LPAD ('Diff', 12)
 84           || LPAD ('Pct', 10));
 85
 86        FOR x
 87           IN (SELECT    TO_CHAR (run1, '999,999,999')
 88                      || TO_CHAR (run2, '999,999,999')
 89                      || TO_CHAR (diff, '999,999,999')
 90                      || TO_CHAR (
 91                            ROUND (
 92                                 run1
 93                               / DECODE (run2, 0, TO_NUMBER (0), run2)
 94                               * 100,
 95                               2),
 96                            '99,999.99')
 97                      || '%'
 98                         data
 99                 FROM (SELECT SUM (b.VALUE - a.VALUE) run1,
100                              SUM (c.VALUE - b.VALUE) run2,
101                              SUM ( (c.VALUE - b.VALUE) - (b.VALUE - a.VALUE)
)
102                                 diff
103                         FROM run_stats a, run_stats b, run_stats c
104                        WHERE     a.name = b.name
105                              AND b.name = c.name
106                              AND a.runid = 'before'
107                              AND b.runid = 'after 1'
108                              AND c.runid = 'after 2'
109                              AND a.name LIKE 'LATCH%'))
110        LOOP
111           DBMS_OUTPUT.put_line (x.data);
112        END LOOP;
113     END;
114  END;
115  /
 
程序包体已创建。
 
SQL>
      上面操作创建了一个测试环境,包括创建用户、相关表,以及一个捕获 SQL 执行中的统计数据的存储过程。
测试对比

    创建一个表 t。

SQL> CREATE TABLE t (x INT);
 
表已创建。
 
SQL>

    创建不使用变量绑定方式执行 SQL 10000 的存储过程 p1:

SQL> CREATE OR REPLACE PROCEDURE p1
  2  AS
  3     l_cnt   NUMBER;
  4  BEGIN
  5     FOR i IN 1 .. 10000
  6     LOOP
  7        EXECUTE IMMEDIATE 'select count(*) from t where x=' || i INTO l_cnt;
  8     END LOOP;
  9  END;
 10  /
 
过程已创建。
 
SQL>

    创建使用变量绑定方式执行 SQL 10000 的存储过程 p2:

SQL> CREATE OR REPLACE PROCEDURE p2
  2  AS
  3     l_cnt   NUMBER;
  4  BEGIN
  5     FOR i IN 1 .. 10000
  6     LOOP
  7        SELECT COUNT(*)
  8          INTO l_cnt
  9          FROM t
 10         WHERE x = i;
 11     END LOOP;
 12  END;
 13  /
 
过程已创建。
 
SQL>
开始测试

SQL> exec runstats_pkg.rs_start
 
PL/SQL 过程已成功完成。
 
SQL> exec p1
 
PL/SQL 过程已成功完成。
 
SQL> exec runstats_pkg.rs_middle
 
PL/SQL 过程已成功完成。
 
SQL> exec p2
 
PL/SQL 过程已成功完成。
 
SQL> exec runstats_pkg.rs_stop(1000)
 
PL/SQL 过程已成功完成。
 
SQL> set serveroutput on
SQL> exec runstats_pkg.rs_stop(1000)
Run1 ran in 379 cpu hsecs
Run2 ran in 26 cpu hsecs
run 1 ran in 1457.69% of the time
 
Name                                  Run1        Run2        Diff
LATCH.channel operations paren       1,622         516      -1,106
STAT...bytes sent via SQL*Net          279       1,443       1,164
LATCH.JS queue state obj latch       1,770         540      -1,230
LATCH.channel operations paren       1,622         245      -1,377
LATCH.JS queue state obj latch       1,770         270      -1,500
LATCH.checkpoint queue latch         2,323         782      -1,541
LATCH.messages                       2,642       1,005      -1,637
LATCH.checkpoint queue latch         2,323         314      -2,009
LATCH.messages                       2,642         380      -2,262
STAT...undo change vector size       2,736       5,376       2,640
STAT...redo size                     3,704       7,252       3,548
LATCH.SQL memory manager worka       6,784       2,109      -4,675
LATCH.SQL memory manager worka       6,784       1,018      -5,766
STAT...physical read bytes               0       8,192       8,192
STAT...physical read total byt           0       8,192       8,192
LATCH.transaction allocation        14,349       4,784      -9,565
STAT...session logical reads        40,074      30,488      -9,586
STAT...consistent gets              40,020      30,422      -9,598
STAT...consistent gets from ca      40,020      30,422      -9,598
STAT...consistent gets from ca      40,018      30,333      -9,685
STAT...calls to get snapshot s      50,009      40,092      -9,917
LATCH.MinActiveScn Latch            10,096         157      -9,939
STAT...parse count (total)          10,009          29      -9,980
STAT...parse count (hard)           10,003          13      -9,990
STAT...enqueue releases             10,010          18      -9,992
STAT...enqueue requests             10,011          18      -9,993
STAT...consistent gets from ca      40,020      30,022      -9,998
STAT...consistent gets              40,020      30,022      -9,998
STAT...parse count (hard)           10,003           4      -9,999
STAT...session cursor cache hi           4      10,004      10,000
STAT...consistent gets from ca      40,018      30,018     -10,000
STAT...parse count (total)          10,009           9     -10,000
STAT...calls to get snapshot s      50,009      40,008     -10,001
STAT...enqueue releases             10,010           6     -10,004
STAT...enqueue requests             10,011           6     -10,005
STAT...session logical reads        40,074      30,054     -10,020
STAT...session cursor cache hi           4      10,031      10,027
LATCH.MinActiveScn Latch            10,096           4     -10,092
LATCH.transaction allocation        14,349       2,391     -11,958
LATCH.cache buffers chains          48,608      34,131     -14,477
STAT...session uga memory           16,424           0     -16,424
STAT...sorts (rows)                      0      17,422      17,422
LATCH.cache buffers chains          48,608      30,643     -17,965
STAT...session uga memory max       13,600      32,072      18,472
LATCH.kks stats                     20,013          28     -19,985
LATCH.kks stats                     20,013           9     -20,004
STAT...Elapsed Time                 29,521       9,331     -20,190
LATCH.enqueue hash chains           24,596       1,966     -22,630
LATCH.enqueues                      24,106       1,392     -22,714
LATCH.enqueues                      24,106         634     -23,472
LATCH.enqueue hash chains           24,596         684     -23,912
STAT...Elapsed Time                 29,521       4,567     -24,954
STAT...recursive calls              40,064      10,361     -29,703
STAT...recursive calls              40,064      10,044     -30,020
STAT...table scan rows gotten            0      34,776      34,776
LATCH.DML lock allocation           63,719      21,430     -42,289
LATCH.DML lock allocation           63,719      10,597     -53,122
LATCH.shared pool simulator         56,264       1,025     -55,239
LATCH.shared pool simulator         56,264         222     -56,042
STAT...session pga memory         -171,272     -65,536     105,736
STAT...session uga memory max       13,600     157,536     143,936
STAT...session pga memory         -171,272           0     171,272
LATCH.row cache objects            182,579       1,796    -180,783
LATCH.row cache objects            182,579         384    -182,195
LATCH.shared pool                  334,118      11,762    -322,356
LATCH.shared pool                  334,118      10,499    -323,619
STAT...session pga memory max   -1,490,300           0   1,490,300
STAT...session pga memory max   -1,490,300   2,293,760   3,784,060
 
Run1 latches total versus runs -- difference and pct
Run1        Run2        Diff       Pct
1,603,990     147,130  -1,456,860  1,090.19%
 
PL/SQL 过程已成功完成。
 
SQL>

    性能采集包 runstats_pkg 分别在测试开始、存储过程 p1 运行结束、存储过程 p2运行结束,这3个时间点采集性能数据,最后在报告中给出了2个存储过程各自的 Latch资源使用情况以及对比情况。

    从这个结果中可以清楚地看到不绑定变量的 Latch 争用是非常严重的,注意输出结果中几个关于 Latch 列 的 Latch 在数量的差异,可以看到,绑定变量要比不绑定,Latch 争用小得多。

下载 runstats.rar

原文地址:https://www.cnblogs.com/liuning8023/p/2983512.html