JDBC PreparedStatement的Performance问题,setString 和 varchar/nvarchar的关系

近期为了解决一些security的问题,把DAO层JDBC的Statement全部替换为PreparedStatement,然后遇到一个非常奇怪的问题是,一个简单的SQL, 比如

SELECT * FROM MDC_DATA_TYPE WHERE name = 'A' AND number = 1;

改成使用SELECT * FROM MDC_DATA_TYPE WHERE name = ? AND number = ?之后,执行时间几乎慢了100倍,这几乎与业界推荐使用PreparedStatement的事实背道而驰。于是花了很多时间来找原因。

 

后来找了曾在微软做SQL Server TCS的同事帮忙看,果然是高手,查看了执行计划 (Execution Plan),这里我留一些备忘:

select spid,status,hostname,program_name,text from sys.sysprocesses p
cross apply sys.dm_exec_sql_text(p.sql_handle) t
where spid>50 and program_name like 'JSQL%'
and program_name like 'JSQL%'
order by spid


select * from sys.dm_exec_requests r
cross apply sys.dm_exec_sql_text(r.sql_handle)
where session_id>50



dbcc freeproccache
dbcc freesystemcache('All')
dbcc dropcleanbuffers
dbcc freeproccache

kill 102

select * from sys.dm_exec_quests

 

// 下面这个是找到找到问题的SQL
select * from sys.dm_exec_cached_plans p
cross apply sys.dm_exec_sql_text(p.plan_handle)
cross apply sys.dm_exec_query_plan(p.plan_handle)

 

可以看到SQLServer缓存的sql:
(@P0 nvarchar(4000),@P1 int,@P2 nvarchar(4000))SELECT * FROM MDC_DATA_TYPE WHERE rmname = @P0 AND numPeriods = @P1 AND periodUnit = @P2 

 

根本原因:

http://www.newatlanta.com/c/support/servletexec/self_help/faq/detail?faqId=183

PreparedStatement.setString() performs more slowly than PreparedStatement.setBytes(). Why?

 

 This can occur when the SQL Server data type of your table's column is different than the type being used in your query.

For example, say you have a table in your SQL Server database with a column of type char or varchar, and the query in your Java code looks like this:
"SELECT * from mytable where mytext = ?"
If you use pstmt.setString(1, "99"); in your Java code, then JTurbo inserts the parameter and builds the query using 'N' like this:
... where mytext = N'99'
This forces SQL Server to do a conversion from nvarchar to the type of your table's column (char or varchar).
A conversion like this is expensive.
If you use pstmt.setBytes(1, "99".getBytes("8859_1")); in your Java code, then JTurbo inserts the parameter and builds the query like this:
... where mytext = 0x3939
which does not require a type conversion within SQL Server.
The only way that JTurbo's PreparedStatement could avoid prepending the 'N' would be if it were to first ask SQL Server whether or not the column type was nchar, nvarchar, or ntext. Asking this for every sql query it builds could be very expensive.

Our recommendation is that you change your database column type to be one of the 'n' types:
  • nchar
  • nvarchar
  • ntext
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值