- 浏览: 605170 次
- 性别:
- 来自: 北京
最新评论
-
黑色幽默_cool:
这种不负责任的文章,多看一分钟都是浪费。
为什么使用ibatis而不用spring jdbcTemplate -
leibinhui:
不错啊 非常实用
JS正则表达式详解[收藏] -
suu:
写个存储过程,爆如下错误,是不是游标里的数据太多引起的?无法执 ...
使用Spring jdbc template调用Sybase带有返回结果集的储存过程-要点 -
travellers:
有SVR6了,为什么很多还在使用SVR4呢?
什么是SVR4?我们为什么要选择SVR4? -
dotjar:
生活是多么美好阿!
老公日记
从开始写java程序就一直被灌输着一种思想,如果使用jdbc一定要使用PreparedStatement,而不要使用Statement对象。
其中的原因有好多,比如可以防止SQL注入攻击,防止数据库缓冲池溢出,代码的可读性,可维护性。这些都很正确。
但是还有一点人们经常提的就是PreparedStatement能够显著的提高执行效率。
看了两篇关于PreparedStatement和Statement的帖子
http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=121&threadID=10397&start=0&tstart=0
http://www.iteye.com/topic/5631?page=1
里面提到,PreparedStatement并不一定比Statement快,于是想自己动手测试一下
一共分5种情况测试
分析:
第一种情况:
由于我测试时采用jdbc直接链接数据库,所以在第一种情况下插入速度很慢,时间都消耗在了数据库链接的创建上了,符合常理,没什么疑义。
第二种情况:
由于使用Statement插入时sql语句都相同,我通过阅读上面的两篇帖子,猜想可能是Statement语句也被DB缓存了,所以跟
PreparedStatement速度差不多,我想如果每次插入的sql都不同,那么Statement应该慢下来了吧。
第三种情况:
并非像我在执行第二种情况时想象的那样,PreparedStatement还是跟Statement差不多,于是我想是不是数据量不够大呀,于是我增大了
插入数据量,希望PreparedStatement能够比Statement快些
第四/五种情况:
测试结果PreparedStatement反到更慢了。
PreparedStatement什么情况下才会比Statement快?那位大侠来指点一下!
代码如下:
DDL
测试程序
所以我们要用connection pool
不是同一个问题。
我们做的这个事情,并不能证明日常编程中应该使用Statement而不是PreparedStatement,相反,我觉得仍然是PreparedStatement更合适。有很多理由,1.防止SQL injection,2.自动类型转换,而获得更好的可移植性;3.更好的性能(尤其是对Oracle,MySQL不一定)
但我们的意义在于,深入理解一些常识背后的知识,而且我们发现有些常识不是那么准确的。
这个问题就象很多Java技术书籍里讲String的知识一样,很多细节不是看上去那样的,不是那么统一的。
现在的问题并不是不能模拟生产环境,而是Robbin提出的方案过于难以实现,或者代价太大。
什么叫“做一个真实的web应用”?具体有什么特性?
还要用Statement实现一遍,再用PreparedStatement改写一遍?
我难以做到这样的测试,但另一方面,你们也难以执行你们的方案以证明你们的观点。所以这样的方案对于我们来说,由于操作性低,这才是无意义的。
我们可以做较复杂的SQL测试,也可以多线程的压力测试。唯独难以做到“真实的应用”,假使做到了一个真实的,你又可以说你那种是特例,又需要在什么什么情况下再测试。其实你们所谓的真实应用,最多也不过是某一类应用,不能代表所有的情况,不是么?
不辩不明事理
良好的编程习惯是什么?习惯又由何而来?
何况楼主、lucas和很多人,都是基于测试数据在进行怀疑,没有任何不好的地方
是的,MySQL4.1以后就支持服务端的Prepared Statement了。
我搞错了,我之前的信息来源是:mysql-connector-java-5.0.3/docs/connect-j.pdf中的:
PreparedStatements are implemented by the driver, as MySQL does not have a prepared statement
feature. Because of this, the driver does not implement getParameterMetaData() or getMetaData() as
it would require the driver to have a complete SQL parser in the client.
Starting with version 3.1.0 MySQL Connector/J, server-side prepared statements and 'binary-encoded'
result sets are used when the server supports them.
之前理解错了。JDBC driver是当MySQL不支持服务端Prepared Statement时(MySQL4.1之前),在Driver里实现这个特性;而当MySQL支持时(MySQL4.1之后),使用服务端的特性。
可以参考这个:http://dev.mysql.com/tech-resources/articles/4.1/prepared-statements.html
虽然MySQL5支持服务端precomiple,但它实现得还比较弱啊,相对于Statement我至今没看出性能提升,相反更弱。
PreparedStatement 更重要的功能是防sql 注入.
这点我同意
PreparedStatement 更重要的功能是防sql 注入.
In Embedded SQL, dynamic statements are SQL statements that need to be compiled at runtime, rather than statically. Typically, dynamic statements contain input parameters, although this is not a requirement. In SQL, the prepare command is used to precompile a dynamic statement and save it so that it can be executed repeatedly without being recompiled during a session. If a statement is used multiple times in a session, precompiling it provides better performance than sending it to the database and compiling it for each use. The more complex the statement, the greater the performance benefit.If a statement is likely to be used only a few times, precompiling it may be inefficient because of the overhead involved in precompiling, saving, and later deallocating it in the database.Precompiling a dynamic SQL statement for execution and saving it in memory uses time and resources. If a statement is not likely to be used multiple times during a session, the costs of doing a database prepare may outweigh its benefits. Another consideration is that once a dynamic SQL statement is prepared in the database, it is very similar to a stored procedure. In some cases, it may be preferable to create stored procedures and have them reside on the server, rather than defining prepared statements in the application.
1:在Sybase中,PreparedStatement是基于Session存储的,一个被编译好的dynSQL语句只对一个session有效,对于那些在一个Session中多次使用的dynSQL语句,使用PreparedStatement会带来性能的提升,sql越复杂使用频率越高,性能提升越大。但是如果一个dynSQL语句在一个Session下被调用的次数少,那么PreparedStatement有可能会导致性能的下降,因为编译,存储,销毁dynSQL语句也是花时间的。
2:在一个session中被编译好的dynSQL其执行效率跟储存过程的效率相似,唯一不同的是PreparedStatement编译好的dynSQL是session有效,而存储过程是全数据库有效。
3:在我上面的测试中我是采用直接连数据库的方式,所以分3次执行使用PreparedStatement的数据库插入操作每次都会重新编译,而且在测试结束时还要负责销毁编译好的查询,这也许是PreparedStatement败下阵来的原因,采用robbin的测试方法,并且sql写的很复杂,那么PreparedStatement也许会有更好的性能
我想,你的这个经验是在oracle上得到的,我在Oracle上也得到了相同的经验,(我在前面的帖子中提及了),
但是,每个数据库是不同的,特别是,MySQL数据库本身并没有PreparedStatemet特性,这一点可以从MySQL JDBC Driver的reference里查到,所以至少,在MySQL上使用PreparedStatement在理论上就没有任何优势,更甚的是,
从我们的测试来看,在MySQL上使用PreparedStatement会比Statement慢一倍左右。
你不认为,了解到不同数据库在这一点上有着较大的差别,是有意义的么?
其中的原因有好多,比如可以防止SQL注入攻击,防止数据库缓冲池溢出,代码的可读性,可维护性。这些都很正确。
但是还有一点人们经常提的就是PreparedStatement能够显著的提高执行效率。
看了两篇关于PreparedStatement和Statement的帖子
http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=121&threadID=10397&start=0&tstart=0
http://www.iteye.com/topic/5631?page=1
里面提到,PreparedStatement并不一定比Statement快,于是想自己动手测试一下
一共分5种情况测试
stmt pre-stmt --1:每次都单独连数据库--100条 21.936 22.076 22.05 22.051 22.172 22.178 --2:Stmt使用相同的SQL语句,参数值也相同--100条 0.78 0.796 0.718 0.749 0.749 0.764 --3:Stmt使用相同的SQL语句,参数值不同--100条 0.967 0.749 0.78 0.874 0.749 0.749 --4:Stmt使用相同的SQL语句,参数值也相同--10000条 33.079 36.154 34.156 39.306 34.359 36.138 --5:Stmt使用相同的SQL语句,参数值不同--10000条 32.799 34.125 32.564 35.53 35.701 34.952 32.582 40.798 38.893 42.345 35.082 41.736
分析:
第一种情况:
由于我测试时采用jdbc直接链接数据库,所以在第一种情况下插入速度很慢,时间都消耗在了数据库链接的创建上了,符合常理,没什么疑义。
第二种情况:
由于使用Statement插入时sql语句都相同,我通过阅读上面的两篇帖子,猜想可能是Statement语句也被DB缓存了,所以跟
PreparedStatement速度差不多,我想如果每次插入的sql都不同,那么Statement应该慢下来了吧。
第三种情况:
并非像我在执行第二种情况时想象的那样,PreparedStatement还是跟Statement差不多,于是我想是不是数据量不够大呀,于是我增大了
插入数据量,希望PreparedStatement能够比Statement快些
第四/五种情况:
测试结果PreparedStatement反到更慢了。
PreparedStatement什么情况下才会比Statement快?那位大侠来指点一下!
代码如下:
DDL
CREATE TABLE dbo.jdbc_stmt ( id numeric(10,0) IDENTITY, name varchar(10) NOT NULL, grad int NOT NULL, age int NOT NULL, dept int NOT NULL )
测试程序
public void jdbcStmtPerformance() { //1:每次都单独连数据库--100条 // String stmtSQL = "insert into jdbc_stmt values('ivanl',2,25,1001)"; // for(int i = 0; i< 100; i++) // { // logger.debug("stmt #"+i); // getJdbcTemplate().update(stmtSQL); // } //2:Stmt使用相同的SQL语句,参数值也相同--100条 // getJdbcTemplate().execute(new StatementCallback(){ // public Object doInStatement(Statement stmt) throws SQLException // { // String stmtSQL = "insert into jdbc_stmt values('ivanl',2,25,1001)"; // for(int i = 0; i< 100; i++) // { // logger.debug("stmt #"+i); // stmt.executeUpdate(stmtSQL); // } // return null; // } // }); //3:Stmt使用相同的SQL语句,参数值不同--100条 // getJdbcTemplate().execute(new StatementCallback(){ // public Object doInStatement(Statement stmt) throws SQLException // { // String stmtSQL = "insert into jdbc_stmt values('ivanl',2,25,"; // for(int i = 0; i< 100; i++) // { // logger.debug("stmt #"+i); // stmt.executeUpdate(stmtSQL+i+")"); // } // return null; // } // }); // 4:Stmt使用相同的SQL语句,参数值也相同--10000条 // getJdbcTemplate().execute(new StatementCallback(){ // public Object doInStatement(Statement stmt) throws SQLException // { // String stmtSQL = "insert into jdbc_stmt values('ivanl',2,25,1001)"; // for(int i = 0; i< 10000; i++) // { // logger.debug("stmt #"+i); // stmt.executeUpdate(stmtSQL); // } // return null; // } // }); // 5:Stmt使用相同的SQL语句,参数值不同--10000条 getJdbcTemplate().execute(new StatementCallback(){ public Object doInStatement(Statement stmt) throws SQLException { String stmtSQL = "insert into jdbc_stmt values('ivanl',2,25,"; for(int i = 0; i< 10000; i++) { logger.debug("stmt #"+i); stmt.executeUpdate(stmtSQL+i+")"); } return null; } }); } public void jdbcPreStmtPerformance() { //1:每次都单独连数据库--100条 // String stmtSQL = "insert into jdbc_stmt values(?,?,?,?)"; // for(int i = 0; i< 100; i++) // { // logger.debug("pre-stmt #"+i); // getJdbcTemplate().update(stmtSQL, new Object[]{"ivanl", new Integer(2), new Integer(25), new Integer(1002)}); // } //2:Stmt使用相同的SQL语句,参数值也相同--100条 // String stmtSQL = "insert into jdbc_stmt values(?,?,?,?)"; // getJdbcTemplate().execute(stmtSQL,new PreparedStatementCallback(){ // public Object doInPreparedStatement(PreparedStatement ps) throws SQLException // { // for(int i = 0; i< 100; i++) // { // logger.debug("pre-stmt #"+i); // ps.setString(1, "ivanl"); // ps.setInt(2, 2); // ps.setInt(3, 25); // ps.setInt(4, 1002); // ps.execute(); // } // return null; // } // }); //3:Stmt使用相同的SQL语句,参数值不同--100条 // String stmtSQL = "insert into jdbc_stmt values(?,?,?,?)"; // getJdbcTemplate().execute(stmtSQL,new PreparedStatementCallback(){ // public Object doInPreparedStatement(PreparedStatement ps) throws SQLException // { // for(int i = 0; i< 100; i++) // { // logger.debug("pre-stmt #"+i); // ps.setString(1, "ivanl"); // ps.setInt(2, 2); // ps.setInt(3, 25); // ps.setInt(4, i); // ps.execute(); // } // return null; // } // }); //4:Stmt使用相同的SQL语句,参数值也相同--10000条 // String stmtSQL = "insert into jdbc_stmt values(?,?,?,?)"; // getJdbcTemplate().execute(stmtSQL,new PreparedStatementCallback(){ // public Object doInPreparedStatement(PreparedStatement ps) throws SQLException // { // for(int i = 0; i< 10000; i++) // { // logger.debug("pre-stmt #"+i); // ps.setString(1, "ivanl"); // ps.setInt(2, 2); // ps.setInt(3, 25); // ps.setInt(4, 1002); // ps.execute(); // } // return null; // } // }); //5:Stmt使用相同的SQL语句,参数值不同--10000条 String stmtSQL = "insert into jdbc_stmt values(?,?,?,?)"; getJdbcTemplate().execute(stmtSQL,new PreparedStatementCallback(){ public Object doInPreparedStatement(PreparedStatement ps) throws SQLException { for(int i = 0; i< 10000; i++) { logger.debug("pre-stmt #"+i); ps.setString(1, "ivanl"); ps.setInt(2, 2); ps.setInt(3, 25); ps.setInt(4, i); ps.execute(); } return null; } }); }
评论
49 楼
wplqw
2007-08-18
PreparedStatement可以避免拼sql的时候那些讨厌的引号和字符串连接符,而且将sql文本的书写与参数的绑定分开,代码清晰很多。以前用delphi的时候,一直就是用参数法查询的。
48 楼
dmewy
2007-08-08
Statement 在select语句的时候比PreparedStatement效率高.
其他的都是PreparedStatement高.
其他的都是PreparedStatement高.
47 楼
seantan
2007-03-01
有书提到过,不过是针对oracle
http://www.onjava.com/pub/a/onjava/excerpt/oraclejdbc_19/index.html?page=2
按照JDBC规范的想法,实际上preparedstatement的出现主要的目的是为了提高SQL语句的的性能,而防止SQL注入和类型转换实际上并不是规范原本的目标。但是实践中这两个功能却受到更多的欢迎。
preparedstatment性能是否能提高性能,实际要具体的看数据库服务器端处理复杂SQL的情况,对于oracle而言在复杂的SQL上面二者性能差异明显(可以使用报表系统的SQL来测试),而比较简单的数据库MySQL和PostgreSQL其的性能提升不明显。在这些某些版本的JDBC实现Preparedstatement的实现就是直接使用statment的实现。
http://www.onjava.com/pub/a/onjava/excerpt/oraclejdbc_19/index.html?page=2
按照JDBC规范的想法,实际上preparedstatement的出现主要的目的是为了提高SQL语句的的性能,而防止SQL注入和类型转换实际上并不是规范原本的目标。但是实践中这两个功能却受到更多的欢迎。
preparedstatment性能是否能提高性能,实际要具体的看数据库服务器端处理复杂SQL的情况,对于oracle而言在复杂的SQL上面二者性能差异明显(可以使用报表系统的SQL来测试),而比较简单的数据库MySQL和PostgreSQL其的性能提升不明显。在这些某些版本的JDBC实现Preparedstatement的实现就是直接使用statment的实现。
46 楼
lszone
2007-03-01
执行次数较多的sql,还是用pstmt快
45 楼
IvanLi
2007-03-01
pcdos 写道
connection关闭后,PreparedStatement就失去了作用,如果是一个connection那ps的效果就出来了
据说mysql的ps最终也是拼装字符串,所以效率反而差点
据说mysql的ps最终也是拼装字符串,所以效率反而差点
所以我们要用connection pool
44 楼
pcdos
2007-03-01
connection关闭后,PreparedStatement就失去了作用,如果是一个connection那ps的效果就出来了
据说mysql的ps最终也是拼装字符串,所以效率反而差点
据说mysql的ps最终也是拼装字符串,所以效率反而差点
43 楼
smilesmith
2007-02-09
昨天和公司的oracle dba讨论过oracle sql执行的具体细节:oracle 执行sql时,首先要分析sql生成查询计划,具体有:分析sql的合法性(到数据库schema中查询),决定使用某个的哪段索引(好像是这样说的)... ...,然后在第一次查询时,用物理读,其后相同的查询计划都是逻辑读,是到缓存里面读。
所以我想PreparedStatement是不是有利于oracle生成查询计划,或许还有别的帮助,所以提高了性能。
但有一点是肯定的,PreparedStatement一定需要driver具体实现才行,Prepared是缓存在数据库端的,要看看oracle jdbc驱动的实现代码才有发言权吧。
另外:我们讨论这些,纯粹是要理解jdbc具体的细节,和操作数据库的底层实现,这些应该是基础知识吧。知其然,并知其所以然。
所以我想PreparedStatement是不是有利于oracle生成查询计划,或许还有别的帮助,所以提高了性能。
但有一点是肯定的,PreparedStatement一定需要driver具体实现才行,Prepared是缓存在数据库端的,要看看oracle jdbc驱动的实现代码才有发言权吧。
另外:我们讨论这些,纯粹是要理解jdbc具体的细节,和操作数据库的底层实现,这些应该是基础知识吧。知其然,并知其所以然。
42 楼
LucasLee
2007-01-25
downpour 写道
我觉得很莫名,MySQL是否支持PrepareStatement和你是否使用PrepareStatement根本就是两回事。我绝对不会因为MySQL某个版本不支持的特性而改变一个良好的编程习惯,更何况,楼上的这种测试事实上没有任何实际意义。正如Robbin所说,你如何模拟生产环境呢?
不是同一个问题。
我们做的这个事情,并不能证明日常编程中应该使用Statement而不是PreparedStatement,相反,我觉得仍然是PreparedStatement更合适。有很多理由,1.防止SQL injection,2.自动类型转换,而获得更好的可移植性;3.更好的性能(尤其是对Oracle,MySQL不一定)
但我们的意义在于,深入理解一些常识背后的知识,而且我们发现有些常识不是那么准确的。
这个问题就象很多Java技术书籍里讲String的知识一样,很多细节不是看上去那样的,不是那么统一的。
现在的问题并不是不能模拟生产环境,而是Robbin提出的方案过于难以实现,或者代价太大。
什么叫“做一个真实的web应用”?具体有什么特性?
还要用Statement实现一遍,再用PreparedStatement改写一遍?
我难以做到这样的测试,但另一方面,你们也难以执行你们的方案以证明你们的观点。所以这样的方案对于我们来说,由于操作性低,这才是无意义的。
我们可以做较复杂的SQL测试,也可以多线程的压力测试。唯独难以做到“真实的应用”,假使做到了一个真实的,你又可以说你那种是特例,又需要在什么什么情况下再测试。其实你们所谓的真实应用,最多也不过是某一类应用,不能代表所有的情况,不是么?
41 楼
kabbesy
2007-01-25
downpour 写道
我觉得很莫名,MySQL是否支持PrepareStatement和你是否使用PrepareStatement根本就是两回事。我绝对不会因为MySQL某个版本不支持的特性而改变一个良好的编程习惯,更何况,楼上的这种测试事实上没有任何实际意义。正如Robbin所说,你如何模拟生产环境呢?
不辩不明事理
良好的编程习惯是什么?习惯又由何而来?
何况楼主、lucas和很多人,都是基于测试数据在进行怀疑,没有任何不好的地方
40 楼
downpour
2007-01-25
我觉得很莫名,MySQL是否支持PrepareStatement和你是否使用PrepareStatement根本就是两回事。我绝对不会因为MySQL某个版本不支持的特性而改变一个良好的编程习惯,更何况,楼上的这种测试事实上没有任何实际意义。正如Robbin所说,你如何模拟生产环境呢?
39 楼
LucasLee
2007-01-25
alin_ass 写道
哪里有说不支持了?
http://dev.mysql.com/doc/refman/5.0/en/sqlps.html
13.7. SQL Syntax for Prepared Statements
MySQL 5.0 provides support for server-side prepared statements. This support takes advantage of the efficient client/server binary protocol implemented in MySQL 4.1, provided that you use an appropriate client programming interface. Candidate interfaces include the MySQL C API client library (for C programs), MySQL Connector/J (for Java programs), and MySQL Connector/NET.
http://dev.mysql.com/doc/refman/5.0/en/sqlps.html
13.7. SQL Syntax for Prepared Statements
MySQL 5.0 provides support for server-side prepared statements. This support takes advantage of the efficient client/server binary protocol implemented in MySQL 4.1, provided that you use an appropriate client programming interface. Candidate interfaces include the MySQL C API client library (for C programs), MySQL Connector/J (for Java programs), and MySQL Connector/NET.
是的,MySQL4.1以后就支持服务端的Prepared Statement了。
我搞错了,我之前的信息来源是:mysql-connector-java-5.0.3/docs/connect-j.pdf中的:
PreparedStatements are implemented by the driver, as MySQL does not have a prepared statement
feature. Because of this, the driver does not implement getParameterMetaData() or getMetaData() as
it would require the driver to have a complete SQL parser in the client.
Starting with version 3.1.0 MySQL Connector/J, server-side prepared statements and 'binary-encoded'
result sets are used when the server supports them.
之前理解错了。JDBC driver是当MySQL不支持服务端Prepared Statement时(MySQL4.1之前),在Driver里实现这个特性;而当MySQL支持时(MySQL4.1之后),使用服务端的特性。
可以参考这个:http://dev.mysql.com/tech-resources/articles/4.1/prepared-statements.html
虽然MySQL5支持服务端precomiple,但它实现得还比较弱啊,相对于Statement我至今没看出性能提升,相反更弱。
38 楼
alin_ass
2007-01-25
哪里有说不支持了?
http://dev.mysql.com/doc/refman/5.0/en/sqlps.html
13.7. SQL Syntax for Prepared Statements
MySQL 5.0 provides support for server-side prepared statements. This support takes advantage of the efficient client/server binary protocol implemented in MySQL 4.1, provided that you use an appropriate client programming interface. Candidate interfaces include the MySQL C API client library (for C programs), MySQL Connector/J (for Java programs), and MySQL Connector/NET.
http://dev.mysql.com/doc/refman/5.0/en/sqlps.html
13.7. SQL Syntax for Prepared Statements
MySQL 5.0 provides support for server-side prepared statements. This support takes advantage of the efficient client/server binary protocol implemented in MySQL 4.1, provided that you use an appropriate client programming interface. Candidate interfaces include the MySQL C API client library (for C programs), MySQL Connector/J (for Java programs), and MySQL Connector/NET.
37 楼
liangguanhui
2007-01-25
噩耗:mysql原来不支持PreparedStatement特性
36 楼
LucasLee
2007-01-24
我在google上查了很久,没有我想要的PreparedStatement vs. statement的全面比较。
大部分都是泛泛的说PreparedStatement理论上怎么怎么样。
找到一个对于MySQL JDBC的讨论:
http://www.mysqltalk.org/statements-vs-preparedstatements-vt112753.html
基本上说的是,Oracle里基本上始终是PreparedStatement性能更好,而MySQL则不是。
大部分都是泛泛的说PreparedStatement理论上怎么怎么样。
找到一个对于MySQL JDBC的讨论:
http://www.mysqltalk.org/statements-vs-preparedstatements-vt112753.html
基本上说的是,Oracle里基本上始终是PreparedStatement性能更好,而MySQL则不是。
35 楼
IvanLi
2007-01-24
codeutil 写道
PreparedStatement 更重要的功能是防sql 注入.
这点我同意
34 楼
codeutil
2007-01-24
PreparedStatement 更重要的功能是防sql 注入.
33 楼
IvanLi
2007-01-24
引用
In Embedded SQL, dynamic statements are SQL statements that need to be compiled at runtime, rather than statically. Typically, dynamic statements contain input parameters, although this is not a requirement. In SQL, the prepare command is used to precompile a dynamic statement and save it so that it can be executed repeatedly without being recompiled during a session. If a statement is used multiple times in a session, precompiling it provides better performance than sending it to the database and compiling it for each use. The more complex the statement, the greater the performance benefit.If a statement is likely to be used only a few times, precompiling it may be inefficient because of the overhead involved in precompiling, saving, and later deallocating it in the database.Precompiling a dynamic SQL statement for execution and saving it in memory uses time and resources. If a statement is not likely to be used multiple times during a session, the costs of doing a database prepare may outweigh its benefits. Another consideration is that once a dynamic SQL statement is prepared in the database, it is very similar to a stored procedure. In some cases, it may be preferable to create stored procedures and have them reside on the server, rather than defining prepared statements in the application.
1:在Sybase中,PreparedStatement是基于Session存储的,一个被编译好的dynSQL语句只对一个session有效,对于那些在一个Session中多次使用的dynSQL语句,使用PreparedStatement会带来性能的提升,sql越复杂使用频率越高,性能提升越大。但是如果一个dynSQL语句在一个Session下被调用的次数少,那么PreparedStatement有可能会导致性能的下降,因为编译,存储,销毁dynSQL语句也是花时间的。
2:在一个session中被编译好的dynSQL其执行效率跟储存过程的效率相似,唯一不同的是PreparedStatement编译好的dynSQL是session有效,而存储过程是全数据库有效。
3:在我上面的测试中我是采用直接连数据库的方式,所以分3次执行使用PreparedStatement的数据库插入操作每次都会重新编译,而且在测试结束时还要负责销毁编译好的查询,这也许是PreparedStatement败下阵来的原因,采用robbin的测试方法,并且sql写的很复杂,那么PreparedStatement也许会有更好的性能
32 楼
codeutil
2007-01-24
我在 Oracle 下的测试结果:
数据库: Oracle9i Enterprise Edition Release 9.2.0.1.0
jdbc驱动 : ojdbc14.jar
数据库表结构脚本:
主键序列:
生成测试数据的sql:
共生成10万条数据.
在plsql中查看会话观察到的
Statement执行的sql为: select t.*, t.rowid from stmtuser t where t.userno= 3277 (变化的数字)
select t.*, t.rowid from stmtuser t where t.userno= :1 (使用的占位符)
第一轮测试, Statement和PreparedStatement各创建一个连接.
循环内每次创建stmt,并关闭stmt
第一次:
执行 500 次Statement操作耗费的时间为3594
执行 500 次PreparedStatement操作耗费的时间为3125
第二次:
执行 5000 次Statement操作耗费的时间为17985
执行 5000 次PreparedStatement操作耗费的时间为12625
第三次:
执行 50000 次Statement操作耗费的时间为154094
执行 50000 次PreparedStatement操作耗费的时间为113188
第二轮测试,Statement和PreparedStatement各创建一个连接.各只创建一次stmt
第一次:
执行 500 次Statement操作耗费的时间为2875
执行 500 次PreparedStatement操作耗费的时间为938
第二次:
执行 5000 次Statement操作耗费的时间为19453
执行 5000 次PreparedStatement操作耗费的时间为6031
第三次:
执行 50000 次Statement操作耗费的时间为155250
执行 50000 次PreparedStatement操作耗费的时间为43891
附件是测试的 java 文件:
数据库: Oracle9i Enterprise Edition Release 9.2.0.1.0
jdbc驱动 : ojdbc14.jar
数据库表结构脚本:
create table STMTUSER ( USERNO NUMBER default 0 not null, USERNAME VARCHAR2(40) default '无名无名无名无名' not null, EMAIL VARCHAR2(100) default 'abcdefg@gmail.com' not null, PHONE VARCHAR2(21) default '1388888888888' ) ; alter table STMTUSER add constraint PK_STMTUSER_USERNO primary key (USERNO);
主键序列:
create sequence SEQ_STMTUSER_ID minvalue 1 maxvalue 999999999999999999999999999 start with 100021 increment by 1 cache 20;
生成测试数据的sql:
insert into stmtuser (userno) values(SEQ_STMTUSER_ID.Nextval);
共生成10万条数据.
在plsql中查看会话观察到的
Statement执行的sql为: select t.*, t.rowid from stmtuser t where t.userno= 3277 (变化的数字)
select t.*, t.rowid from stmtuser t where t.userno= :1 (使用的占位符)
第一轮测试, Statement和PreparedStatement各创建一个连接.
循环内每次创建stmt,并关闭stmt
第一次:
执行 500 次Statement操作耗费的时间为3594
执行 500 次PreparedStatement操作耗费的时间为3125
第二次:
执行 5000 次Statement操作耗费的时间为17985
执行 5000 次PreparedStatement操作耗费的时间为12625
第三次:
执行 50000 次Statement操作耗费的时间为154094
执行 50000 次PreparedStatement操作耗费的时间为113188
第二轮测试,Statement和PreparedStatement各创建一个连接.各只创建一次stmt
第一次:
执行 500 次Statement操作耗费的时间为2875
执行 500 次PreparedStatement操作耗费的时间为938
第二次:
执行 5000 次Statement操作耗费的时间为19453
执行 5000 次PreparedStatement操作耗费的时间为6031
第三次:
执行 50000 次Statement操作耗费的时间为155250
执行 50000 次PreparedStatement操作耗费的时间为43891
附件是测试的 java 文件:
31 楼
LucasLee
2007-01-24
robbin 写道
是的,你们确实做了无用功。测试的目的在于指导实践。就单个请求来说statement要快,但是如果按照这种思路去写代码,后果是很严重的。因为会对数据库服务器造成很重的压力,系统吞吐量也要降低。早在2001年的时候,我维护的一个系统(访问量巨大,每天上百万),Oracle数据库每周都要宕机一次,经过几个月的排查,最终找到的原因就是我们程序所有的条件查询全部都是statement拼SQL字符串。全部改掉以后恢复正常,性能也明显提高。
实际的应用程序都是多用户并发的web应用,不是单机自己一个人用的,你们那种测试根本就不能反应实际的多用户并发的系统吞吐量和数据库负载情况,不是误导是什么?
实际的应用程序都是多用户并发的web应用,不是单机自己一个人用的,你们那种测试根本就不能反应实际的多用户并发的系统吞吐量和数据库负载情况,不是误导是什么?
我想,你的这个经验是在oracle上得到的,我在Oracle上也得到了相同的经验,(我在前面的帖子中提及了),
但是,每个数据库是不同的,特别是,MySQL数据库本身并没有PreparedStatemet特性,这一点可以从MySQL JDBC Driver的reference里查到,所以至少,在MySQL上使用PreparedStatement在理论上就没有任何优势,更甚的是,
从我们的测试来看,在MySQL上使用PreparedStatement会比Statement慢一倍左右。
你不认为,了解到不同数据库在这一点上有着较大的差别,是有意义的么?
30 楼
Allen
2007-01-24
刚才查了一下,MySQL Connector/J Docs 中确实有写到:
所以我在想,是不是在建立MySQL的JDBC连接时,对Driver中PreparedStatement相关属性(例如cachePrepStmts)的配置应该会对将来的性能有不小的影响?
引用
PreparedStatement
PreparedStatements are implemented by the driver, as MySQL does not have a prepared statement feature. Because of this, the driver does not implement getParameterMetaData() or getMetaData() as it would require the driver to have a complete SQL parser in the client.
Starting with version 3.1.0 MySQL Connector/J, server-side prepared statements and binary-encoded result sets are used when the server supports them.
PreparedStatements are implemented by the driver, as MySQL does not have a prepared statement feature. Because of this, the driver does not implement getParameterMetaData() or getMetaData() as it would require the driver to have a complete SQL parser in the client.
Starting with version 3.1.0 MySQL Connector/J, server-side prepared statements and binary-encoded result sets are used when the server supports them.
所以我在想,是不是在建立MySQL的JDBC连接时,对Driver中PreparedStatement相关属性(例如cachePrepStmts)的配置应该会对将来的性能有不小的影响?
发表评论
-
use hibernate3-maven to export sql based on entity
2011-08-07 18:19 1404<plugin> <group ... -
uninstall mysql completely in my Mac X 10.6
2011-08-07 12:19 1220sudo rm /usr/local/mysql ... -
my vimrc
2011-05-14 11:02 1720copy from http://www.vi-improve ... -
使用HSQLDB来作EJB3 EntityBean到Unit Test要点
2010-01-20 17:17 2118add <property name=" ... -
user xrandr to change my desktop's resolution
2009-12-16 17:04 1686xrandr --newmode "1280x ... -
XSS的关键之列表
2009-10-11 17:20 1836//this field are used tp esc ... -
python查看方法帮助(from dive into python)
2009-09-30 11:31 2630def info(object, spanding=10, c ... -
selenium 测试ajax的关键
2009-01-20 18:26 42411: waitForCondition(contidtion, ... -
RichFaces 手记
2008-10-07 15:46 0安装,除了richfaces 下载包中的jar( " ... -
代码检查工具
2008-09-25 11:48 2563findBugs, PMD, CheckStyle find ... -
CI工具hudson
2008-09-24 17:04 3123CI工具除了hudson,还有很多,例如CruiseContr ... -
创建solaris package step by step
2008-09-24 11:27 1927原文地址:http://www.ibiblio.org/pub ... -
什么是SVR4?我们为什么要选择SVR4?
2008-09-23 14:13 4972http://www.lslnet.com/linux/f/d ... -
IPS 中的pkg command学习笔记
2008-09-22 17:18 1852pkg(1): 使用pkg(1)来创建一个镜像,安装,升级,管 ... -
On Board前的学习计划
2008-09-18 09:37 15251:在virtual box 上虚拟一个OpenSolaris ... -
YUI Grid CSS的优雅设计
2008-09-02 22:38 2827最近加入了一个GAE的项目cpedialog,该项目的前端布局 ... -
我很懒,但是懒人有懒办法
2008-08-18 17:06 1812今天要使用jackrabbit做个小东西,上apache一看, ... -
当XPath遇上NameSpace
2008-07-23 19:39 6567在jdk5.0中,已经包含了对Xpath的支持,可一通过下面的 ... -
ubuntu下安装ipmsg-飞鸽传书
2008-07-21 09:32 28891 先下载 源码 下载的是gnome2版本的源码 http ... -
sudo 执行时无密码(不安全)
2008-07-17 17:18 2216sudo visudo root ALL=(ALL) ...
相关推荐
Java 中 PreparedStatement 和 Statement 的区别 Java 中的 PreparedStatement 和 Statement 都是用于执行 SQL 语句的接口,但是它们之间存在一些关键的区别。 首先,从数据库执行 SQL 语句的角度来看,使用 ...
这种差异导致PreparedStatement对象执行速度更快,特别是在执行多次相同的SQL语句时。 其次,PreparedStatement对象可以避免SQL注入攻击。在 Statement 对象中,如果用户输入的数据包含恶意代码,例如 Drop 表名,...
jdbc中preparedStatement比Statement的好处
- **性能**:由于预编译,`PreparedStatement`通常比`Statement`更快,尤其是在大量重复执行相同SQL时。 - **安全性**:`PreparedStatement`通过占位符防止SQL注入,而`Statement`则容易受到这类攻击。 - **...
Java面试题34.jdbc中preparedStatement比Statement的好处.mp4
`PreparedStatement`是`Statement`接口的子接口,用于预编译SQL语句,并可以重复执行这些预编译过的SQL语句。这不仅能够提高应用程序的性能,还能提高安全性,因为它支持参数化查询,避免了SQL注入的风险。 #### 二...
一种可能的方法是通过日志配置,例如,启用MySQL的`Statement`和`PreparedStatement`日志,这样在执行时会打印出详细的SQL语句。 另外,开发工具如IntelliJ IDEA、Eclipse等,或者数据库管理工具如MySQL Workbench...
### PreparedStatement的详细...综上所述,无论从性能、安全性还是数据库无关性的角度,`PreparedStatement`都是比`Statement`更为优秀的选择,因此,在实际开发中,应尽可能地采用`PreparedStatement`来执行SQL语句。
#### 何时使用 Statement? - 当SQL语句简单,不会重复执行时。 - 对于读取数据的操作,如果数据量不大,可以考虑使用`Statement`。 - 当不需要参数化SQL语句时,例如只读操作。 #### 何时使用 PreparedStatement...
首先,从创建时的区别开始,Statement 需要通过 Connection 对象的 createStatement() 方法创建,而 PreparedStatement 需要通过 Connection 对象的 prepareStatement() 方法创建,并且需要带有 SQL 语句。...
`PreparedStatement`的主要特点在于它可以预先编译SQL语句,并允许用户在执行前动态地设置SQL语句中的参数值,这使得它在执行相同或相似SQL语句时比普通的`Statement`更加高效。 #### 二、`PreparedStatement`与`...
NULL 博文链接:https://chaoyi.iteye.com/blog/2088080
在Java编程语言中,`PreparedStatement`是`java.sql`包中的一个接口,它继承自`Statement`类,并提供了预编译SQL语句的功能。预编译SQL语句的主要优势在于提高了执行效率和安全性。尤其在处理动态查询或频繁执行相同...
PreparedStatement对象的创建和预编译过程比Statement更为复杂和耗时。因此,在那些对性能要求极高且SQL语句几乎不重复执行的应用场景下,或许需要根据具体情况来权衡利弊。 总之,理解Statement和...
在Java编程中,PreparedStatement是Java SQL API中的一个接口,它是Statement接口的子接口。这个练习主要涉及如何使用PreparedStatement来插入宠物信息到数据库中。PreparedStatement的主要优势在于它的预编译能力和...
在Java的JDBC(Java Database Connectivity)中,与数据库交互的核心接口是Statement和PreparedStatement。这两个接口都是用于执行SQL语句的,但它们在特性和效率上有所不同。 Statement接口是最基本的SQL执行方式...
在实际开发中,为了提高效率和安全性,我们通常会使用PreparedStatement接口来代替Statement接口。 1. **PreparedStatement简介** PreparedStatement是Statement的一个子接口,它的主要优势在于预编译。预编译的...
### PreparedStatement 向数据库插入时间方法 #### 背景与问题描述 在Java应用程序中,我们经常需要将数据写入数据库。为了确保SQL查询的安全性和效率,通常会使用`PreparedStatement`来执行这样的操作。然而,在...
在数据库编程中,我们经常遇到两种执行SQL语句的方法:Statement和PreparedStatement。尽管Statement看起来更简洁,但在实际应用中,尤其是在使用ORM框架如MyBatis时,PreparedStatement成为了首选。那么,为什么...