论坛首页 Java企业应用论坛

PreparedStatement真的比Statement快吗?

浏览 43632 次
精华帖 (2) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (1)
作者 正文
   发表时间:2007-01-24  
刚才查了一下,MySQL Connector/J Docs 中确实有写到:
引用
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.

所以我在想,是不是在建立MySQL的JDBC连接时,对Driver中PreparedStatement相关属性(例如cachePrepStmts)的配置应该会对将来的性能有不小的影响?
0 请登录后投票
   发表时间:2007-01-24  
robbin 写道
是的,你们确实做了无用功。测试的目的在于指导实践。就单个请求来说statement要快,但是如果按照这种思路去写代码,后果是很严重的。因为会对数据库服务器造成很重的压力,系统吞吐量也要降低。早在2001年的时候,我维护的一个系统(访问量巨大,每天上百万),Oracle数据库每周都要宕机一次,经过几个月的排查,最终找到的原因就是我们程序所有的条件查询全部都是statement拼SQL字符串。全部改掉以后恢复正常,性能也明显提高。

实际的应用程序都是多用户并发的web应用,不是单机自己一个人用的,你们那种测试根本就不能反应实际的多用户并发的系统吞吐量和数据库负载情况,不是误导是什么?



我想,你的这个经验是在oracle上得到的,我在Oracle上也得到了相同的经验,(我在前面的帖子中提及了),
但是,每个数据库是不同的,特别是,MySQL数据库本身并没有PreparedStatemet特性,这一点可以从MySQL JDBC Driver的reference里查到,所以至少,在MySQL上使用PreparedStatement在理论上就没有任何优势,更甚的是,
从我们的测试来看,在MySQL上使用PreparedStatement会比Statement慢一倍左右。

你不认为,了解到不同数据库在这一点上有着较大的差别,是有意义的么?
0 请登录后投票
   发表时间:2007-01-24  
我在 Oracle 下的测试结果:

数据库: 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 文件:



  • StmtTest.zip (917 Bytes)
  • 描述: Statement与PreparedStatement比较
  • 下载次数: 51
0 请登录后投票
   发表时间: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也许会有更好的性能
0 请登录后投票
   发表时间:2007-01-24  

PreparedStatement 更重要的功能是防sql 注入.

0 请登录后投票
   发表时间:2007-01-24  
codeutil 写道

PreparedStatement 更重要的功能是防sql 注入.


这点我同意
0 请登录后投票
   发表时间:2007-01-24  
我在google上查了很久,没有我想要的PreparedStatement vs. statement的全面比较。
大部分都是泛泛的说PreparedStatement理论上怎么怎么样。

找到一个对于MySQL JDBC的讨论:
http://www.mysqltalk.org/statements-vs-preparedstatements-vt112753.html
基本上说的是,Oracle里基本上始终是PreparedStatement性能更好,而MySQL则不是。
0 请登录后投票
   发表时间:2007-01-25  
噩耗:mysql原来不支持PreparedStatement特性
0 请登录后投票
   发表时间: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.
0 请登录后投票
   发表时间: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.


是的,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我至今没看出性能提升,相反更弱。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics