参数化与Sqlserver2008

参数化与Sqlserver2008

近段时间,发生了线上出现Sqlserver服务器CPU占用过高的情况,从sqlserver的活动监视器中可以查看到对应的消耗语句:
select top 1 name,sex,address from consult_info with(nolock) where name = @P0 (consult_info 数据量接近1000万),
Sqlserver Profiler具体的执行语句是:
select top 1 name,sex,address from consult_info with(nolock) where name = N’陈名’

使用语句查询统计数据:
set statistics io on
set statistics time on
select top 1 name,sex,address from consult_info with(nolock) where name = N’陈名’
结果:
扫描计数 1,逻辑读取 33957 次,物理读取 62 次,预读 29330 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
SQL Server 执行时间:
CPU 时间 = 500 毫秒,占用时间 = 8194 毫秒。
SQL Server 分析和编译时间:
CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。
SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。

使用参数化的查询方式,不管是java、c#,语句都会自动在字符前面增加N,并把类型定义为nvachar(name数据库中是定义为varchar)。
exec sp_executesql N’ select top 1 name,sex,address from consult_info with(nolock) where name =@name ‘,N’@name nvarchar(20)’,@name =N’陈名’

验证后的情况:
当只有在查询中包含中文字符,才会出现逻辑读取次数较多,CPU占用时间较长的情况出现,加N和不加N执行计划是一样的。
当查询中不包含中文字符,逻辑读取次数,CPU占用时间,加N和不加N是一样的。
还有不确定的一点,和索引是否有关系。
这里写图片描述
(执行计划中会多出图中标红的部分)

解决的方法:
1:参数化查询的方式,程序上修改为直接采用字符串拼接的方式。(注意加上校验,防止sql注入风险)
结果如下:
扫描计数 1,逻辑读取 8 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 97 毫秒。
SQL Server 分析和编译时间:
CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。
SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。

2、在数据库层面,把name的varchar修改为nvarchar类型。

PS:问题虽然处理了,但是未能搞明白,具体的原理是什么? 另外,据说在sqlserver高版本中已经解决了此问题(未验证)。

参考资料:
https://www.cnblogs.com/sword-successful/p/5543626.html

猜你喜欢

转载自blog.csdn.net/fengaodlw/article/details/80547386