[转帖]Oracle JDBC中的语句缓存

oracle,jdbc,语句,缓存 · 浏览次数 : 0

小编点评

**Oracle性能优化方法** **1. 降低 SQL 解析数量** * 使用 **`STATEMENT_CACHE_SIZE`** 属性设置语句缓存大小。 * 使用 **`AUTOCOMMIT`** 属性禁用自动提交,以降低并发执行对性能的影响。 * 使用 **`OPTIMIZE FOR CACHE`** 语句优化查询执行计划。 **2. 使用查询缓存** * 创建一个存储查询结果的缓存表。 * 在查询过程中读取缓存中已执行的查询结果。 * 使用 **`PreparedStatement`** 的 `queryCache` 属性设置查询缓存大小。 **3. 使用结果缓存** * 在查询过程中缓存查询结果。 * 在使用结果之前,清理缓存。 * 使用 **`PreparedStatement`** 的 `resultSetCache` 属性设置结果缓存大小。 **4. 使用手工控制** * 使用 **`setStatementCacheSize()`** 设置语句缓存大小。 * 使用 **`setImplicitCachingEnabled()`** 设置隐式缓存。 * 使用 **`setExplicitCachingEnabled()`** 设置手工控制缓存。 **示例代码** ```java // 设置语句缓存大小 ((OracleConnection)conn).setStatementCacheSize(20); // 设置隐式打开语句缓存 ((OracleConnection)conn).setImplicitCachingEnabled(true); // 设置手工控制缓存 ((OraclePreparedStatement)pstmt).setExplicitCachingEnabled(true); ``` **注意** * 在使用任何缓存之前,应确保数据完整性和一致性。 * 缓存的利用效率可能会有所波动,取决于查询的复杂性和数据规模。 * 优化性能是一个逐步的过程,应从小的更改开始。

正文

 

在Oracle数据库中,SQL解析有几种:

  • 硬解析,过多的硬解析在系统中产生shared pool latch和library cache liatch争用,消耗过多的shared pool,使得系统不具有可伸缩性。
  • 软解析,过多的软解析仍然可能会导致系统问题,特别是如果有少量的SQL高并发地进行软解析,会产生library cache latch或者是share方式的mutex争用。
  • 软软解析,其实这也也属于软解析,与普通的软解析不同的是,软软解析的SQL会在会话的cached cursor中命中。
  • 一次解析,多次执行,这是解析次数最少的方式,也是系统最具有可扩展性的方式。

那么在JAVA开发的应用中,怎么样才能实现上述第4种方式?如果是循环处理某种数据,这个比较容易实现。其实对于不是这种情况,Oracle也提供了很好的方式来实现这一点。下面是一个例子(例子代码文件为TestStmtCache.java)。

import java.sql.*;
import oracle.jdbc.driver.OracleConnection;

public class TestStmtCache {
    public static Connection getConnection() throws Exception {
        String driver = "oracle.jdbc.driver.OracleDriver";
        String url = "jdbc:oracle:thin:@localhost:1521:xj11g";
        Class.forName(driver);
        return DriverManager.getConnection(url, "test", "test");
    }

    public static void main(String args[]) {
        Connection conn = null;
        try {
            conn = getConnection();
            conn.setAutoCommit(false);
            ((OracleConnection)conn).setStatementCacheSize(0);
            for (int i=0; i <200; i++) {
                testNoCache(conn);
            }
            ((OracleConnection)conn).setStatementCacheSize(20);
            ((OracleConnection)conn).setImplicitCachingEnabled(true);

            for (int i=0; i <200; i++) {
                testCache(conn);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    public static void testCache(Connection conn) {
        PreparedStatement pstmt = null;
        try {
            pstmt = conn.prepareStatement("select /*cache_test1 */ * from t1 where rownum<=1");
            pstmt.execute();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                pstmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    public static void testNoCache(Connection conn) {
        PreparedStatement pstmt = null;
        try {
            pstmt = conn.prepareStatement("select /*nocache_test1 */ * from t1 where rownum<=1");
            pstmt.execute();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                pstmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

编译上述代码文件TestStmtCache.java,并运行:

E:\JavaCode>set CLASSPATH=.;ojdbc14.jar

E:\JavaCode>d:\works\Java\jdk1.5.0_21\bin\javac TestStmtCache.java

E:\JavaCode>d:\works\Java\jdk1.5.0_21\jre\bin\java TestStmtCache

在数据库中进行查询:

SYS@xj11g> select sql_id,parse_calls,executions,sql_text from v$sqlarea where sql_text like '%cache_test%' and sql_text not like '%v$%';

SQL_ID        PARSE_CALLS  EXECUTIONS SQL_TEXT
------------- ----------- ----------- ------------------------------------------------------------
3nbu9qp40ptjk         200         200 select /*nocache_test1 */ * from t1 where rownum< =1
47hja0fwmmb6c           1         200 select /*cache_test1 */ * from t1 where rownum<=1

可以看到,这两条SQL语句,都执行了200次,但是标记为"nocache_test1"的SQL没有进行语句缓存,其parse calls为200次,即解析了200次,其中一次是硬解析。而标记为"cache_test1"的SQL语句,使用了语句缓存,但是parse calls只有1次,即只有一次硬解析,执行了200次。这里关键的代码在于:

            ((OracleConnection)conn).setStatementCacheSize(20);
            ((OracleConnection)conn).setImplicitCachingEnabled(true);

上述第一行代码设置语句缓存大小,当然20比较偏小,对于比较大型的系统来说,设到200-300比较合适,不过这会耗用一定数量的JAVA内存。这个数值表示一个连接能够缓存多少语句。第二行代码是设置隐式打开语句缓存,也即自动会对PreparedStatement的SQL语句进行缓存。

那么,上述的方式无疑是比较简单的,但是这种方式有一个问题就是,缓存的利用效率可能不高,因为JAVA会将不常用的SQL语句也进行了缓存。Oracle的JDBC驱动也提供了一种手工控制的方式:
将测试代码中的第22行替换为:

((OracleConnection)conn).setExplicitCachingEnabled(true);

第40行替换为:

pstmt = ((OracleConnection)conn).getStatementWithKey ("cache_test1");
if (pstmt==null)

第46行替换为:

((OraclePreparedStatement)pstmt).closeWithKey ("cache_test1");

这样通过手工编码的方式控制哪些语句需要缓存,哪些不需要。
关于语句缓存(Statement Caching)可以参考Oracle在线文档:Statement and Result Set Caching

 
jdbc

与[转帖]Oracle JDBC中的语句缓存相似的内容:

[转帖]Oracle JDBC中的语句缓存

老熊 Oracle性能优化 2013-09-13 在Oracle数据库中,SQL解析有几种: 硬解析,过多的硬解析在系统中产生shared pool latch和library cache liatch争用,消耗过多的shared pool,使得系统不具有可伸缩性。 软解析,过多的软解析仍然可能会导

[转帖]OJDBC版本区别 [ojdbc14.jar,ojdbc5.jar和ojdbc6.jar的区别]

classes12.jar,ojdbc14.jar,ojdbc5.jar和ojdbc6.jar的区别,之间的差异 在使用Oracle JDBC驱动时,有些问题你是不是通过替换不同版本的Oracle JDBC驱动来解决的?最常使用的ojdbc14.jar有多个版本,classes12.jar有多个版本

[转帖]Jmeter之JDBC Request使用方法(oracle)

https://zhuanlan.zhihu.com/p/121747788 JDBC Request: 这个sampler可以向数据库发送一个jdbc请求(sql语句),它经常需要和JDBC Connection Configuration 配置元件一起配合使用。 目录: 一、准备工作 二、配置J

[转帖]使用JAYDEBEAPI同时连接两个不同数据库(ORACLE+MYSQL)的问题

jaydebeapi 同时连接两种数据库 在使用jaydebeapi只连接一种数据库时,是没问题的,但是如果需要同时连接两种数据库,比如同时连接oracle和mysql 例如以下测试代码: import jaydebeapi ##使用jdbc驱动连接数据库 import pandas as pd d

[转帖]Oracle Linux 9 - Oracle 提供支持 RHEL 兼容发行版

https://sysin.org/blog/oracle-linux-9/ Oracle Linux 是一个开放、全面的操作环境,提供虚拟化、管理、云原生计算工具和操作系统,通过一个统一的支持解决方案满足您的业务需求。Oracle Linux 与 Red Hat Enterprise Linux

[转帖]Oracle数据库的两种授权收费方式详解

https://www.jb51.net/article/265823.htm 现在Oracle有两种授权收费方式,按CPU(Process)数和按用户数(Named User Plus),前一种方式一般用于用户数不确定或者用户数量很大的情况,典型的如互联网环境,这篇文章主要介绍了Oracle数据库

[转帖]Oracle jdk与OpenJdk

https://www.jianshu.com/p/ca5e7f78eb4e ————Oracle JDK———————jdk历史叫Sun Jdk,后来被Oracle收购后现在叫做Oracle JDKOracleJDK由Oracle公司开发维护,该公司是Sun许可证,基于Java标准版规范实现。它以

[转帖]oracle清理临时表空间

https://blog.51cto.com/u_11310506/2357625 为了防止临时表空间无限制的增加,我采用隔一段时间就重建临时表空间的方法,为了方便,我保留两组语句,轮流执行即可, 假定现在临时表空间名称是temp,新建一个tempa表空间,删除temp表空间,方法如下: alter

[转帖]Oracle、MySQL、PG是如何处理数据库“半页写”的问题的?

数据库“断页”是个很有意思的话题,目前任何数据库应该都绕不过去。我们知道数据库的块大小一般是8k、16k、32k,而操作系统块大小是4k,那么在数据库刷内存中的数据页到磁盘上的时候,就有可能中途遭遇类似操作系统异常断电而导致数据页部分写的情况,进而造成数据块损坏,数据块损坏对于某些数据库是致命的,可

[转帖]Oracle查看所有用户及其权限

https://www.cnblogs.com/huazhixu/p/15788803.html Oracle查看所有用户及其权限:Oracle数据字典视图的种类分别为:USER,ALL 和 DBA.USER_*:有关用户所拥有的对象信息,即用户自己创建的对象信息ALL_*:有关用户可以访问的对象的