• 11g新特性-查询缓存(1)


    众所周知,访问内存比访问硬盘快得多,除非硬盘体系发生革命性的改变。可以说缓存在Oracle里面无处不在,结果集缓存(Result Cache)是Oracle Database 11g新引入的功能,引入它的目的在于可以重用相同的结果集,减少逻辑IO,提高系统性能。结果集缓存又分为:服务端缓存和客户端缓存。

    一、服务端缓存

    1.服务器端的Result Cache Memorey由两部分组成。
    (1)SQL Query Result Cache:存储SQL查询的结果集。
    (2)PL/SQL Function Result Cache:用于存储PL/SQL函数的结果集。

    2.相关的初始化参数:

    SQL> show parameter result

    NAME TYPE VALUE
    ------------------------------------ ---------------------- ------------------------------
    client_result_cache_lag big integer 3000
    client_result_cache_size big integer 0
    result_cache_max_result integer 5
    result_cache_max_size big integer 10M
    result_cache_mode string MANUAL
    result_cache_remote_expiration integer 0

    带client的是客户端的参数,剩下的是服务端的相关参数。

    2.1 首先,服务端的结果集缓存的开关,是参数result_cache_max_size。当result_cache_max_size=0的时候,代表不启用结果集缓存。

    它的大小,默认值取决于其它内存设置(memory_target的0.25% 或sga_target 的0.5% 或shared_pool_size 的1%)

    2.2 其次,result_cache_mode 用于控制Server Result cache的模式

    result_cache_mode 有3个值:auto、manual、force

    如果设置的值为MANUAL,用户必须用reslut_cache 提示才可以缓存结果集。
    如果设置为FORCE,ORACLE会缓冲所有的结果,除非用户用了no_result_cache提示。
    如果设置为AUTO,优化器会自动判断是否将查询结果缓存。

    2.3 RESULT_CACHE_MAX_RESULT 

    该参数是控制单个result所能占据RESULT_CACHE_MAX_SIZE的大小比例,注意是一个百分比。
    该参数默认是是5%,取值范围当然是1% ~ 100% 了。

    2.4 result_cache_remote_expiration
    该参数的作用是根据远程数据库对象设置缓存过期的时间,默认值为0.
    也就是说,默认情况下,远程数据库对象不会被进行cache的。

    3.相关视图

    V$RESULT_CACHE_STATISTICS:列出各种缓存设置和内存使用统计数据。
    V$RESULT_CACHE_MEMORY:列出所有的内存块和相应的统计信息。
    V$RESULT_CACHE_OBJECTS:列出所有的对象(缓存的结果和依赖的对象)和它们的属性。
    V$RESULT_CACHE_DEPENDENCY:列出缓存的结果和依赖对象间的依赖详情。

    4.Oracle还提供了一个包来管理server result cache:dbms_result_cache

    4.1查看server result cache的内存使用报告

    SQL> set serveroutput on;

    SQL> exec dbms_result_cache.Memory_Report
    R e s u l t C a c h e M e m o r y R e p o r t
    [Parameters]
    Block Size = 1K bytes
    Maximum Cache Size = 10M bytes (10K blocks)
    Maximum Result Size = 512K bytes (512 blocks)
    [Memory]
    Total Memory = 110476 bytes [0.018% of the Shared Pool]
    ... Fixed Memory = 12080 bytes [0.002% of the Shared Pool]
    ... Dynamic Memory = 98396 bytes [0.016% of the Shared Pool]
    ....... Overhead = 65628 bytes
    ....... Cache Memory = 32K bytes (32 blocks)
    ........... Unused Memory = 0 blocks
    ........... Used Memory = 32 blocks
    ............... Dependencies = 1 blocks (1 count)
    ............... Results = 31 blocks
    ................... SQL = 1 blocks (1 count)
    ................... Invalid = 30 blocks (30 count)

    PL/SQL procedure successfully completed.

    4.2 FLUSH: 清空整个结果缓存的内容。
     
    4.3 INVALIDATE: 使结果缓存中一个特定对象的缓存结果无效。
     
    4.4 INVALIDATE_OBJECT: 根据缓存ID使一特定结果缓存无效。

    5.实验:

    SQL> create table test as select * from dba_objects;
    
    Table created.
    
    SQL> select /*+ result_cache */ owner,count(*) from test group by owner;
    
    28 rows selected.
    
    
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 1435881708
    
    --------------------------------------------------------------------------------------------------
    | Id  | Operation           | Name                       | Rows  | Bytes | Cost (%CPU)| Time     |
    --------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT    |                            | 74795 |  1241K|   291   (2)| 00:00:04 |
    |   1 |  RESULT CACHE       | 6fpdv8pg615sh5j0pw1t1jn3wq |       |       |            |          |
    |   2 |   HASH GROUP BY     |                            | 74795 |  1241K|   291   (2)| 00:00:04 |
    |   3 |    TABLE ACCESS FULL| TEST                       | 74795 |  1241K|   289   (1)| 00:00:04 |
    --------------------------------------------------------------------------------------------------
    
    Result Cache Information (identified by operation id):
    ------------------------------------------------------
    
       1 - column-count=2; dependencies=(TEST.TEST); parameters=(nls); name="select /*+ result_cache */
     owner,count(*) from test group by owner"
    
    
    Note
    -----
       - dynamic sampling used for this statement (level=2)
    
    
    Statistics
    ----------------------------------------------------------
             48  recursive calls
              0  db block gets
           1109  consistent gets
           1031  physical reads
              0  redo size
           1035  bytes sent via SQL*Net to client
            430  bytes received via SQL*Net from client
              3  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
             28  rows processed
    
    SQL> select /*+ result_cache */ owner,count(*) from test group by owner;
    
    28 rows selected.
    
    
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 1435881708
    
    --------------------------------------------------------------------------------------------------
    | Id  | Operation           | Name                       | Rows  | Bytes | Cost (%CPU)| Time     |
    --------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT    |                            | 74795 |  1241K|   291   (2)| 00:00:04 |
    |   1 |  RESULT CACHE       | 6fpdv8pg615sh5j0pw1t1jn3wq |       |       |            |          |
    |   2 |   HASH GROUP BY     |                            | 74795 |  1241K|   291   (2)| 00:00:04 |
    |   3 |    TABLE ACCESS FULL| TEST                       | 74795 |  1241K|   289   (1)| 00:00:04 |
    --------------------------------------------------------------------------------------------------
    
    Result Cache Information (identified by operation id):
    ------------------------------------------------------
    
       1 - column-count=2; dependencies=(TEST.TEST); parameters=(nls); name="select /*+ result_cache */
     owner,count(*) from test group by owner"
    
    
    Note
    -----
       - dynamic sampling used for this statement (level=2)
    
    
    Statistics
    ----------------------------------------------------------
              0  recursive calls
              0  db block gets
              0  consistent gets
              0  physical reads
              0  redo size
           1035  bytes sent via SQL*Net to client
            430  bytes received via SQL*Net from client
              3  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
             28  rows processed

    从执行计划中可以看到标黄色的地方,就是对应 v$result_cache_objects的cache_id的。在第二次查询的执行计划中,发现逻辑读已经变成0 了,说明result cache起作用了。

    SQL> exec dbms_result_cache.memory_report    
    R e s u l t   C a c h e   M e m o r y   R e p o r t
    [Parameters]
    Block Size          = 1K bytes
    Maximum Cache Size  = 10M bytes (10K blocks)
    Maximum Result Size = 512K bytes (512 blocks)
    [Memory]
    Total Memory = 110476 bytes [0.018% of the Shared Pool]
    ... Fixed Memory = 12080 bytes [0.002% of the Shared Pool]
    ... Dynamic Memory = 98396 bytes [0.016% of the Shared Pool]
    ....... Overhead = 65628 bytes
    ....... Cache Memory = 32K bytes (32 blocks)
    ........... Unused Memory = 0 blocks
    ........... Used Memory = 32 blocks
    ............... Dependencies = 3 blocks (3 count)
    ............... Results = 29 blocks
    ................... SQL     = 1 blocks (1 count)
    ................... Invalid = 28 blocks (28 count)
    
    PL/SQL procedure successfully completed.
    
    SQL> select * from v$result_cache_statistics;
    
            ID NAME                           VALUE
    ---------- ------------------------------ ------------------------------
             1 Block Size (Bytes)             1024
             2 Block Count Maximum            10240
             3 Block Count Current            32
             4 Result Size Maximum (Blocks)   512
             5 Create Count Success           30166
             6 Create Count Failure           0
             7 Find Count                     3
             8 Invalidation Count             2
             9 Delete Count Invalid           30137
            10 Delete Count Valid             0
            11 Hash Chain Length              1
    
    11 rows selected.
    
    SQL> 

    再来看看相应的report和统计信息。

    SQL> select * from v$result_cache_statistics;
    
            ID NAME                           VALUE
    ---------- ------------------------------ ------------------------------
             1 Block Size (Bytes)             1024
             2 Block Count Maximum            10240
             3 Block Count Current            32
             4 Result Size Maximum (Blocks)   512
             5 Create Count Success           30166
             6 Create Count Failure           0
             7 Find Count                     3
             8 Invalidation Count             2
             9 Delete Count Invalid           30137
            10 Delete Count Valid             0
            11 Hash Chain Length              1
    
    11 rows selected.
    
    SQL> select /*+ result_cache */ owner,count(*) from test group by owner;
    
    OWNER                                                          COUNT(*)
    ------------------------------------------------------------ ----------
    LZQ                                                                   2
    OWBSYS_AUDIT                                                         12
    MDSYS                                                              1509
    PUBLIC                                                            27696
    OUTLN                                                                 9
    TEST                                                                  9
    CTXSYS                                                              366
    OLAPSYS                                                             719
    FLOWS_FILES                                                          12
    OWBSYS                                                                2
    SYSTEM                                                              529
    
    OWNER                                                          COUNT(*)
    ------------------------------------------------------------ ----------
    ORACLE_OCM                                                            8
    EXFSYS                                                              310
    APEX_030200                                                        2406
    SCOTT                                                                 6
    ISC                                                                 558
    DBSNMP                                                               65
    ORDSYS                                                             2532
    ORDPLUGINS                                                           10
    SYSMAN                                                             3491
    SURE                                                                  1
    APPQOSSYS                                                             3
    
    OWNER                                                          COUNT(*)
    ------------------------------------------------------------ ----------
    XDB                                                                 842
    ORDDATA                                                             248
    SS                                                                    1
    SYS                                                               30792
    WMSYS                                                               316
    SI_INFORMTN_SCHEMA                                                    8
    
    28 rows selected.
    
    SQL> select * from v$result_cache_statistics;                           
    
            ID NAME                           VALUE
    ---------- ------------------------------ ------------------------------
             1 Block Size (Bytes)             1024
             2 Block Count Maximum            10240
             3 Block Count Current            32
             4 Result Size Maximum (Blocks)   512
             5 Create Count Success           30226
             6 Create Count Failure           0
             7 Find Count                     4
             8 Invalidation Count             2
             9 Delete Count Invalid           30197
            10 Delete Count Valid             0
            11 Hash Chain Length              1
    
    11 rows selected.
    
    SQL> 

    注意到Find Count = 1,说明上次缓存的结果被后面的查询应用了一次。如果继续执行该查询,可以发现该统计信息会相应增加。

    我们可以根据cache_id去 v$result_cache_objects查询相关的信息 

    SQL> select name,cache_id from v$result_cache_objects t where t.CACHE_ID='6fpdv8pg615sh5j0pw1t1jn3wq'
      2  ;
    
    NAME
    ------------------------------
    CACHE_ID
    ---------------------------------------------------------------------------------------------------
    select /*+ result_cache */ own
    er,count(*) from test group by
     owner
    6fpdv8pg615sh5j0pw1t1jn3wq

    6.深入认识result cache

    query cache result特性所占据的内存是从sga的share pool中分配,如下视图可以看到

    SQL> select * from v$sgastat where lower(name) like '%result%';

    POOL NAME BYTES
    ------------------------ ------------------------- ----------
    shared pool Result Cache: State Objs 5492
    shared pool Result Cache 98396
    shared pool Result Cache: Memory Mgr 124
    shared pool Result Cache: Bloom Fltr 2048
    shared pool Result Cache: Cache Mgr 4416

    result cache也有类似enqueue/lock的保护机制,RC enqueue就是拿来保护并发修改的。result cache依赖是object level的,
    既不是row level的,也不是block level的。任何DML/DDL(甚至包括grant)都会使基于这个object的result cache变为invalidate。
    所以result cache只有对那些在平时几乎没有任何DML的只读表比较有用,可以减轻io的压力。

    在平时读取阶段不是使用的shared pool latch,而是使用的result cache latch,如下所示


    SQL> select * from v$latchname where name like 'Result Cache%';

    LATCH# NAME HASH
    ---------- ------------------------- ----------
    391 Result Cache: RC Latch 1054203712
    392 Result Cache: SO Latch 986859868
    393 Result Cache: MB Latch 995186388

    检查result cache配置是否生效
    1.select dbms_result_cache.status from dual;
    2.dbms_result_cache.MEMORY_REPORT
    3.查看sql执行计划中是否还有关键字:result cache

    注意:
    11g的active dataguard的备库是不能使用result cache的,result cache目前可以使用在单节点主库和rac环境。

    二、客户端查询结果集缓存

    假设有这样一个情形:客户端需要通过慢速网络链接调用同一数据。尽管数据库可以立即将结果从缓存发送到客户端,但结果必须通过线路传送到客户端,这就增加了整体执行时间。现在有一些专门的中间件框架(如 Oracle Coherence),用于在 Java、PHP 和 Ruby 中缓存数据,如果有一个在客户端级别缓存数据的通用方法,又将如何呢?

    为此,Oracle 数据库 11g 提供了“客户端查询结果缓存”。所有使用 OCI8 驱动程序的数据库客户端堆栈(C、C++、JDBC-OCI 等)都可以使用这一新特性,使客户端能够在本地缓存 SQL 查询的结果,而不是在服务器上。总言之,客户端查询结果缓存可以提供以下好处:

    (1)使应用程序开发人员不用构建由所有会话共享的一致的每一流程的 SQL 结果缓存

    (2)通过利用更便宜的客户端内存并在本地缓存每个应用程序的工作集,将服务器端查询缓存扩展到客户端内存,

    (3)从而消除到服务器的往返过程,确保更好的性能

    (4)通过节约服务器资源,改善服务器可伸缩性

    (5)提供透明的缓存管理:内存管理、结果集的并发访问等

    (6)透明地维护缓存与服务器端更改的一致性

    (7)在 RAC 环境中提供一致性

    要使用这一特性,所要做的就是设置一个初始化参数:CLIENT_RESULT_CACHE_SIZE = 1G

    该参数定义客户端缓存为 1GB,这是所有客户端的总缓存大小。(这是一个静态参数,因此必须重启数据库来设置)可以在每个客户端中设置缓存,在客户端位置的 SQLNET.ORA 文件中指定其他参数: 

    让我们看一看它的使用方式。这是简单的 Java 代码,它使用 OCI8 驱动程序连接到数据库,然后执行 SQL 语句:select /*+ result_cache */ * from customers。提示致使语句缓存该结果(其他参数已经设置好)。

    public class CacheTest {
        private String jdbcURL = "jdbc:oracle:oci8:@orcl";
        private Connection conn = null;
        public CacheTest( ) throws ClassNotFoundException {
                Class.forName("oracle.jdbc.driver.OracleDriver");
            }
        public static void main(String[] args) throws ClassNotFoundException, SQLException {
                CacheTest check = new CacheTest();
                check.dbconnect();
                check.doSomething();
            }
        public void dbconnect() throws SQLException {
                System.out.println("Connecting with URL="+jdbcURL+" as arup/arup");
                try {
                    conn = DriverManager.getConnection( jdbcURL, "arup" , "arup");
                    System.out.println("Connected to Database");
                } catch (SQLException sqlEx) {
                    System.out.println(" Error connecting to database : " + sqlEx.toString());
                }
            }
        public void doSomething() throws SQLException {
                Statement stmt = null;
                ResultSet rset = null;
                try {
                    stmt = conn.createStatement();
                    System.out.println("Created Statement object");
                    rset = stmt.executeQuery("select /*+ result_cache */ * from customers");
                    System.out.println("Retrieved ResultSet object");
                    if(rset.next())
                    System.out.println("Result:"+rset.getString(1));
                } catch (SQLException sqlEx) {
                }finally {
                    try {
                        System.out.println("Closing Statment & ResultSet Objects");
                        if (rset != null) rset.close();
                        if (stmt != null) stmt.close();
                        if (conn != null) {
                            System.out.println("Disconnecting...");
                            conn.close();
                            System.out.println("Disconnected from Database");
                        }
                    } catch (Exception e) {}
                }
            }
        }

     PS: OCI8类似于thin,只是它需要在相关的服务器上装上oracle client才能使用。

  • 相关阅读:
    相由心生
    超级唯美的爱情语句(中英)
    有多少人败给“对不起,家里不同意”
    请善待老公,其实男人不容易
    摩托车西藏之旅实战攻略
    女人眼里36种不靠谱男人
    什么是爱?什么是幸福?
    踏板车的节油措施汇总
    史上最无语最蛋疼新闻标题
    太他妈幽默了,丫不去写书真浪费了
  • 原文地址:https://www.cnblogs.com/nazeebodan/p/4093960.html
Copyright © 2020-2023  润新知