转载至: http://www.cnblogs.com/lzrabbit/archive/2012/04/21/2460978.html

错误认识1.不需要防止sql注入的地方无需参数化
  参数化查询就是为了防止SQL注入用的,其它还有什么用途不知道、也不关心,原则上是能不用参数就不用参数,为啥?多麻烦,我只是做公司内部系统不用担心SQL注入风险,使用参数化查询不是给自己找麻烦,简简单单拼SQL,万事OK

错误认识2.参数化查询时是否指定参数类型、参数长度没什么区别
  以前也一直都觉的加与不加参数长度
应该没有什么区别,仅是写法上的不同而已,而且觉得加参数类型和长度写法太麻烦,最近才明白其实两者不一样的,为了提高sql执行速度,请为
SqlParameter参数加上SqlDbType和size属性,在参数化查询代码编写过程中很多开发者忽略了指定查询参数的类型,这将导致托管代码
在执行过程中不能自动识别参数类型,进而对该字段内容进行全表扫描以确定参数类型并进行转换,消耗了不必要的查询性能所致。根据MSDN解释:如果未在
size参数中显式设置Size,则从dbType参数的值推断出该大小。如果你认为上面的推断出该大小是指从SqlDbType类型推断,那你就错了,
它实际上是从你传过来的参数的值来推断的,比如传递过来的值是"username",则size值为8,"username1",则size值为9。那
么,不同的size值会引发什么样的结果呢?且经测试发现,size的值不同时,会导致数据库的执行计划不会重用,这样就会每次执行sql的时候重新生成
新的执行计划,而浪费数据库执行时间。

下面来看具体测试

首先清空查询计划

DBCC FREEPROCCACHE

传值username,不指定参数长度,生成查询计划

using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
SqlCommand comm = new SqlCommand();
comm.Connection = conn;
comm.CommandText = "select * from Users where UserName=@UserName";
//传值 username,不指定参数长度
//查询计划为(@UserName varchar(8))select * from Users where UserName=@UserName
comm.Parameters.Add(new SqlParameter("@UserName", SqlDbType.VarChar) { Value = "username" });
comm.ExecuteNonQuery();
}

传值username1,不指定参数长度,生成查询计划

using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
SqlCommand comm = new SqlCommand();
comm.Connection = conn;
comm.CommandText = "select * from Users where UserName=@UserName";
//传值 username1,不指定参数长度
//查询计划为(@UserName varchar(9))select * from Users where UserName=@UserName
comm.Parameters.Add(new SqlParameter("@UserName", SqlDbType.VarChar) { Value = "username1" });
comm.ExecuteNonQuery();
}

传值username,指定参数长度为50,生成查询计划

using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
SqlCommand comm = new SqlCommand();
comm.Connection = conn;
comm.CommandText = "select * from Users where UserName=@UserName";
//传值 username,指定参数长度为50
//查询计划为(@UserName varchar(50))select * from Users where UserName=@UserName
comm.Parameters.Add(new SqlParameter("@UserName", SqlDbType.VarChar,50) { Value = "username" });
comm.ExecuteNonQuery();
}

传值username1,指定参数长度为50,生成查询计划

using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
SqlCommand comm = new SqlCommand();
comm.Connection = conn;
comm.CommandText = "select * from Users where UserName=@UserName";
//传值 username1,指定参数长度为50
//查询计划为(@UserName varchar(50))select * from Users where UserName=@UserName
comm.Parameters.Add(new SqlParameter("@UserName", SqlDbType.VarChar,50) { Value = "username1" });
comm.ExecuteNonQuery();
}

使用下面语句查看执行的查询计划

SELECT cacheobjtype,objtype,usecounts,sql FROM sys.syscacheobjects
WHERE sql LIKE '%Users%' and sql not like '%syscacheobjects%'

结果如下图所示

可以看到指定了参数长度的查询可以复用查询计划,而不指定参数长度的查询会根据具体传值而改变查询计划,从而造成性能的损失。

这里的指定参数长度仅指可变长数据类型,主要指varchar,nvarchar,char,nchar等,对于 int,bigint,decimal,datetime等定长的值类型来说,无需指定(即便指定了也没有用),详见下面测试,UserID为int类 型,无论长度指定为2、20、-1查询计划都完全一样为(@UserIDint)select*from Users where UserID=@UserID

using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
SqlCommand comm = new SqlCommand();
comm.Connection = conn;
comm.CommandText = "select * from Users where UserID=@UserID";
//传值 2,参数长度2
//执行计划(@UserID int)select * from Users where UserID=@UserID
comm.Parameters.Add(new SqlParameter("@UserID", SqlDbType.Int, 2) { Value = 2 });
comm.ExecuteNonQuery();
}
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
SqlCommand comm = new SqlCommand();
comm.Connection = conn;
comm.CommandText = "select * from Users where UserID=@UserID";
//传值 2,参数长度20
//执行计划(@UserID int)select * from Users where UserID=@UserID
comm.Parameters.Add(new SqlParameter("@UserID", SqlDbType.Int, 20) { Value = 2 });
comm.ExecuteNonQuery();
}
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
SqlCommand comm = new SqlCommand();
comm.Connection = conn;
comm.CommandText = "select * from Users where UserID=@UserID";
//传值 2,参数长度-1
//执行计划(@UserID int)select * from Users where UserID=@UserID
comm.Parameters.Add(new SqlParameter("@UserID", SqlDbType.Int, -1) { Value = 2 });
comm.ExecuteNonQuery();
}

这里提一下,若要传值varchar(max)或nvarchar(max)类型怎么传,其实只要设定长度为-1即可

using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
SqlCommand comm = new SqlCommand();
comm.Connection = conn;
comm.CommandText = "select * from Users where UserName=@UserName";
//类型为varchar(max)时,指定参数长度为-1
//查询计划为 (@UserName varchar(max) )select * from Users where UserName=@UserName
comm.Parameters.Add(new SqlParameter("@UserName", SqlDbType.VarChar,-1) { Value = "username1" });
comm.ExecuteNonQuery();
}

当然了若是不使用参数化查询,直接拼接SQL,那样就更没有查询计划复用一说了,除非你每次拼的SQL都完全一样

总结,参数化查询意义及注意点

1.可以防止SQL注入

2.可以提高查询性能(主要是可以复用查询计划),这点在数据量较大时尤为重要

3.参数化查询参数类型为可变长度时(varchar,nvarchar,char等)请指定参数类型及长度,若为值类型(int,bigint,decimal,datetime等)则仅指定参数类型即可

4.传值为varchar(max)或者nvarchar(max)时,参数长度指定为-1即可

5.看到有些童鞋对于存储过程是否要指定参数长度有些疑惑,这里补充下,若调用的是存储过程时,参数无需指定长度,如果指定了也会忽略,以存储过程 中定义的长度为准,不会因为没有指定参数长度而导致重新编译,不过还是建议大家即便时调用存储过程时也加上长度,保持良好的变成习惯

【转】浅析Sql Server参数化查询的更多相关文章

  1. 浅析Sql Server参数化查询

    说来惭愧,工作差不多4年了,直到前些日子被DBA找上门让我优化一个CPU占用很高的复杂SQL语句时,我才突然意识到了参数化查询的重要性. 相信有很多开发者和我一样对于参数化查询认识比较模糊,没有引起足 ...

  2. Sql Server参数化查询之where in和like实现详解

    where in 的参数化查询实现 首先说一下我们常用的办法,直接拼SQL实现,一般情况下都能满足需要 string userIds = "1,2,3,4"; using (Sql ...

  3. 【转】Sql Server参数化查询之where in和like实现之xml和DataTable传参

    转载至: http://www.cnblogs.com/lzrabbit/archive/2012/04/29/2475427.html 在上一篇Sql Server参数化查询之where in和li ...

  4. 【转】Sql Server参数化查询之where in和like实现详解

    转载至:http://www.cnblogs.com/lzrabbit/archive/2012/04/22/2465313.html 文章导读 拼SQL实现where in查询 使用CHARINDE ...

  5. 【转载】Sql Server参数化查询之where in和like实现详解

    文章导读 拼SQL实现where in查询 使用CHARINDEX或like实现where in 参数化 使用exec动态执行SQl实现where in 参数化 为每一个参数生成一个参数实现where ...

  6. Sql Server参数化查询之where in和like实现详解 [转]

    文章导读 拼SQL实现where in查询 使用CHARINDEX或like实现where in 参数化 使用exec动态执行SQl实现where in 参数化 为每一个参数生成一个参数实现where ...

  7. Sql Server参数化查询之where in和like实现之xml和DataTable传参 (转)

    在上一篇Sql Server参数化查询之where in和like实现详解中介绍了在Sql Server使用参数化查询where in的几种实现方案,遗漏了xml和表值参数,这里做一个补充 文章导读 ...

  8. [转]Sql Server参数化查询之where in和like实现详解

    本文转自;http://www.cnblogs.com/lzrabbit/archive/2012/04/22/2465313.html 文章导读 拼SQL实现where in查询 使用CHARIND ...

  9. SQL Server参数化查询中应用Like

    一般情况下是SQL语句: Select * From Users Where UserName Like 'Lin%' Select * From Users Where UserName Like ...

随机推荐

  1. UIscrollView和UIPageControl的循环滚动

    因为昨天在网上找了很久,很多只能实现向右滚动,而且一张图一个imageview ,感觉工作量很可怕啊 ,  下面的例子就是不论你多少图 , 只和我代码里面的几个数值有关,  只需要修改分页和循环i的最 ...

  2. ofbiz 本地化及邮件设置126邮箱

    ofibz登陆功能有通过电子邮件找会密码的功能,但找回密码功能需要配置一个发送email的邮箱账号和smtp服务器的配置,具体配置如下: 1:在ofbiz数据库的表product_store_emai ...

  3. EF深入系列--细节

    1.在调试的时候,查看EF生成的SQL语句 在Context类的构造函数中添加以下代码,就可以在调试的时候在[输出]窗口中看到SQL语句 this.Database.Log = s => Sys ...

  4. SQL Server调优系列基础篇(联合运算符总结)

    前言 上两篇文章我们介绍了查看查询计划的方式,以及一些常用的连接运算符的优化技巧,本篇我们总结联合运算符的使用方式和优化技巧. 废话少说,直接进入本篇的主题. 技术准备 基于SQL Server200 ...

  5. 烂泥:CentOS6.5光盘以及ISO镜像文件的使用

    本文由秀依林枫提供友情赞助,首发于烂泥行天下. 学习CentOS有一段时间了,在平时使用过程中.系统镜像以及光盘使用的比较多,这篇文章就从实用的角度介绍相关有关光盘与镜像文件的使用. 因为物理机相关的 ...

  6. shell流程控制&函数

    条件 if-then-elif-then-fi if的条件部分经常使用test EXPRESSION或[ EXPRESSION ]实现,test的用法可以参见test if 条件1 #if 条件1;t ...

  7. Linux工具之man手册彩色页设置

    说明: 对于我们开发人员或者运维工程师来说,经常要查询某个系统命令或者C函数接口的使用方法,最好的最专业的资料就是man手册,通过一些设置可以让man手册页面显示适当颜色,方便阅读,增强美观性. 设置 ...

  8. x01.os.1: BIOS 中断

    这只是一点准备工作.为了显示字符串,需要调用中断:int  0x10 (AH=0x13).具体参数设置,参考我的归纳整理如下: INT 10 (AH = 0) -----------------功能: ...

  9. Android 播放电影时滑动屏幕调整屏幕亮度(转)

    (转自:http://blog.csdn.net/piaozhiye/article/details/6544450) 发现有一些主流的播放器播放电影时可以通过滑动屏幕调整屏幕亮度,其实实现起来也很容 ...

  10. Altium Desiner 警告 adding hidden net

    这是因为 一些元件 隐藏了 vcc GND 或者没有使用vcc GND ,用不着它也报警告了. 这里可以将 vcc GND删掉这个管脚.