在一些实际项目场景中,有时候会出现数据库内存池中 SQL_CACHE_MANAGERMENT 项使用率较高的情况,我们知道该 sql 缓冲区主要是用来存储 sql 执行计划的。当该项内存池使用比较大时意味着数据库服务端的确接收处理了大量不同种类样式的 sql,而应用发出的 sql 往往存在很多“结构相同,参数值不同”的情况,此时如果将这些相同结构的 sql 解析一次生成执行计划,在不同参数值传进来是多次重复执行可以节省系统开销,提升 sql 执行效率。下面我们来讨论一下在进行 sql 常量参数化过程可能遇到的一些问题和处理方法:
valves 值为常量的 sql
create table test(id int,name varchar(20));
insert into test values(1,‘abc’);
insert into test values(2,‘def’);
commit;
查看计划池或 dmsql 中 sql 是服务端执行的是原封不动的常量 sql 格式。
select cache_item,sqlstr from v$cachepln where sqlstr like ‘%test%’;
valves 值为参数的 sql
SQL> insert into test values(?,?);
请输入参数1的值:3
请输入参数2的值:aaa
影响行数 1
已用时间: 9.595(毫秒). 执行号:12100.
SQL> insert into test values(?,?);
请输入参数1的值:4
请输入参数2的值:bbb
影响行数 1
已用时间: 0.490(毫秒). 执行号:12101.
SQL> commit;
再次查看发现服务端接受的参数化的 sql。
系统全局参数化
有时候应用代码短时间无法改造成参数化的 sql 格式,怎么办呢?达梦提供了打开系统级 sql 常量参数化的方法:设置参数 CLT_CONST_TO_PARAM = 1
CLT_CONST_TO_PARAM = 1
insert into test values(5,'ccc');
insert into test values(6,'ddd');
commit;
此时再次使用常量 sql 进行测试发现自动进行了参数化转换。
由于修改参数重启了数据库服务,所以计划缓存都清理了,sql 依然进行了常量参数化。
Jdbc 程序中 prepareStatement 参数化表现:
如下使用 jdbc 测试程序测试,可以看到并没有将常量参数化。
public void insert(String vId,String vName) throws SQLException {
String vSql = "insert into test values("+ vId + ",'"+ vName + "')";
PreparedStatement pstmt = conn.prepareStatement(vSql);
pstmt.executeUpdate();
pstmt.close();
System.out.println("insert complete!");
}
这里为什么开启了常量参数化后,常量并没有被参数化呢?其实这里与 jdbc 中使用的创建句柄类型有关,我们知道 prepareStatement 表示 sql 语句已经编译好了,对于需要多次重复执行的 SQL 语句经常才会去使用PreparedStatement 对象,也就是说数据库认为“要执行的sql已经是参数化之后的sql”,所以并不会再去进行参数化了。
Jdbc 程序中 createStatement 参数化表现:
将代码中的语句成 createStatement 对象。
public void insert2(String vId,String vName) throws SQLException {
String vSql = "insert into test values("+ vId + ",'"+ vName + "')";
Statement stmt = conn.createStatement();
stmt.executeUpdate(vSql);
stmt.close();
System.out.println("insert complete!");
}
可以看到使用 createStatement 对象时系统还是自动进行了常量参数化转换。
prepareOptimize 的作用
那如果应用的代码就是全部使用的 prepareStatement,短时间也没法改动怎么办呢?Jdbc 中提供了以下参数
我们将改参数加到连接串中 jdbc:dm://127.0.0.1?prepareOptimize=true 再次测试 prepareStatement 的常量参数化情况:此时可以看到开启 prepareOptimize=true 后即使应用是 preparestament 也会进行参数化转换。
总结:
在数据库应用开发过程中,是否对 sql 进行常量参数化设置会影响执行效率和执行计划重用。达梦数据库中提供了以上几种参数化的方法,在实际应用过程中,代码开发最好还是搞清楚不同方法的使用场景,不要混为一谈,虽然常量和参数化都可以使用 prepareStatement,但是会带来一些隐藏问题并在排查的过程中造成一定的困扰。
文章
阅读量
获赞