准备语句如何提高性能

时间:2015-03-25 17:18:12

标签: java oracle jdbc

我在下面的语句中讲述了JDBC PreparedStatement类带来的性能改进。

  

如果为每个查询或更新提交新的完整SQL语句   在数据库中,数据库必须解析SQL并为查询创建   查询计划。通过重用现有的PreparedStatement,您可以重复使用   后续查询的SQL解析和查询计划。这个   通过减少解析和查询来加速查询执行   计划每次执行的开销。

假设我正在创建语句并在运行这样的查询时提供不同的值:

String sql = "update people set firstname=? , lastname=? where id=?";

PreparedStatement preparedStatement =
        connection.prepareStatement(sql);

preparedStatement.setString(1, "Gary");
preparedStatement.setString(2, "Larson");
preparedStatement.setLong  (3, 123);

int rowsAffected = preparedStatement.executeUpdate();

preparedStatement.setString(1, "Stan");
preparedStatement.setString(2, "Lee");
preparedStatement.setLong  (3, 456);

int rowsAffected = preparedStatement.executeUpdate();

然后我仍然会获得性能优势,因为我正在尝试设置不同的值,因此我可以根据值更改生成的最终查询。

您能否详细解释我们何时获得性能优势?值是否应该相同?

2 个答案:

答案 0 :(得分:4)

当你使用预准备语句(即预编译语句)时,一旦DB获得此语句,它就会编译它并对其进行缓存,以便它可以使用最后编译的语句来连续调用同一语句。因此它会为连续调用进行预编译。

您通常使用带有绑定变量的预准备语句,您可以在运行时提供变量。现在,对于连续执行预准备语句会发生什么,您可以提供与先前调用不同的变量。从DB的角度来看,它不必每次都编译语句,只会在朗姆酒时插入绑定变量。所以变得更快。

预准备语句的其他优点是防止SQL注入攻击

因此值不必相同

答案 1 :(得分:0)

虽然不是很明显SQL不是脚本而是“编译”语言。而这个汇编又名。优化又称硬解析是非常详尽的任务。 Oracle有很多工作要做,它必须解析查询,解析表名,验证访问权限,执行一些代数转换,然后必须找到有效的执行计划。 Oracle(以及其他数据库)也只能加入两个表 - 而不是更多。这意味着当您在SQL中连接多个表时,Oracle必须逐个加入它们。即,如果您在查询中加入n个表,则可能至少有n!个可能的执行计划。默认情况下,在搜索“最佳”(不是最佳)执行计划时,Oracle最多限制为8000个排列。

因此编译(硬解析)可能比查询执行本身更详尽。为了节省资源,Oracle在名为库缓存的内存结构中共享会话之间的执行计划。这里可能会出现另一个问题,太多的解析需要独占访问共享资源。 因此,如果您执行太多(硬)解析,您的应用程序无法扩展 - 会话相互阻塞。

另一方面,有些情况下绑定变量没有帮助。 想象一下这样一个问题:

update people set firstname=? , lastname=? where group=? and deleted='N'

由于列deleted已编入索引且Oracle知道有98%的值='Y'且只有2%的值='N',因此它将推断使用列{{1 }}。如果您在deleted列上使用了绑定变量条件,那么Oracle无法找到有效的执行计划,因为它还取决于编译时未知的输入。 (PS:因为11g它更复杂,绑定变量偷看)