我在下面的语句中讲述了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();
然后我仍然会获得性能优势,因为我正在尝试设置不同的值,因此我可以根据值更改生成的最终查询。
您能否详细解释我们何时获得性能优势?值是否应该相同?
答案 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它更复杂,绑定变量偷看)