知识大全 SQL Server参数化查询大数据下的实践

Posted

篇首语:万事须己运,他得非我贤。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 SQL Server参数化查询大数据下的实践相关的知识,希望对你有一定的参考价值。

SQL Server参数化查询大数据下的实践  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  身为一名小小的程序员 在日常开发中不可以避免的要和where in和like打交道 在大多数情况下我们传的参数不多简单做下单引号 敏感字符转义之后就直接拼进了SQL 执行查询 搞定 若有一天你不可避免的需要提高SQL的查询性能 需要一次性where in 几百 上千 甚至上万条数据时 参数化查询将是必然进行的选择 然而如何实现where in和like的参数化查询 是个让不少人头疼的问题

  where in 的参数化查询实现

  首先说一下我们常用的办法 直接拼SQL实现 一般情况下都能满足需要

  string userIds = " ";

  using (SqlConnection conn = new SqlConnection(connectionString))

  

  conn Open();

  SqlCommand m = new SqlCommand();

  m Connection = conn;

  m CommandText = string Format("select * from Users(nolock) where UserID in( )" userIds);

  m ExecuteNonQuery();

  

  需要参数化查询时进行的尝试 很显然如下这样执行SQL会报错错误

  using (SqlConnection conn = new SqlConnection(connectionString))

  

  conn Open();

  SqlCommand m = new SqlCommand();

  m Connection = conn;

  m CommandText = "select * from Users(nolock) where UserID in(@UserID)";

  m Parameters Add(new SqlParameter("@UserID" SqlDbType VarChar ) Value = " " );

  m ExecuteNonQuery();

  

  很显然这样会报错误 在将 varchar 值 转换成数据类型 int 时失败 因为参数类型为字符串 where in时会把@UserID当做一个字符串来处理 相当于实际执行了如下语句

  select * from Users(nolock) where UserID in( )

  若执行的语句为字符串类型的 SQL执行不会报错 当然也不会查询出任何结果

  using (SqlConnection conn = new SqlConnection(connectionString))

  

  conn Open();

  SqlCommand m = new SqlCommand();

  m Connection = conn;

  m CommandText = "select * from Users(nolock) where UserName in(@UserName)";

  m Parameters Add(new SqlParameter("@UserName" SqlDbType VarChar ) Value = " john dudu rabbit " );

  m ExecuteNonQuery();

  

  这样不会抱任何错误 也查不出想要的结果 因为这个@UserName被当做一个字符串来处理 实际相当于执行如下语句

  select * from Users(nolock) where UserName in( john dudu rabbit )

  由此相信 大家对于为何简单的where in 传参无法得到正确的结果知道为什么了吧 下面我们来看一看如何实现正确的参数化执行where in 为了真正实现参数化where in 传参 很多人才想到了各种替代方案

  方案 使用CHARINDEX或like 方法实现参数化查询 毫无疑问 这种方法成功了 而且成功的复用了查询计划 但同时也彻底的让查询索引失效(在此不探讨索引话题) 造成的后果是全表扫描 如果表里数据量很大 百万级 千万级甚至更多 这样的写法将造成灾难性后果;如果数据量比较小 只想借助参数化实现防止SQL注入的话这样写也无可厚非 还是得看具体需求 (不推荐)

  using (SqlConnection conn = new SqlConnection(connectionString))

  

  conn Open();

  SqlCommand m = new SqlCommand();

  m Connection = conn;

  //使用CHARINDEX 实现参数化查询 可以复用查询计划 同时会使索引失效

  m CommandText = "select * from Users(nolock) where CHARINDEX( +ltrim(str(UserID))+ +@UserID+ )> ";

  m Parameters Add(new SqlParameter("@UserID" SqlDbType VarChar ) Value = " " );

  m ExecuteNonQuery();

  

  using (SqlConnection conn = new SqlConnection(connectionString))

  

  conn Open();

  SqlCommand m = new SqlCommand();

  m Connection = conn;

  //使用like 实现参数化查询 可以复用查询计划 同时会使索引失效

  m CommandText = "select * from Users(nolock) where +@UserID+ like % +ltrim(str(UserID))+ % ";

  m Parameters Add(new SqlParameter("@UserID" SqlDbType VarChar ) Value = " " );

  m ExecuteNonQuery();

  

  方案 使用exec动态执行SQL 这样的写法毫无疑问是很成功的 而且代码也比较优雅 也起到了防止SQL注入的作用 看上去很完美 不过这种写法和直接拼SQL执行没啥实质性的区别 查询计划没有得到复用 对于性能提升没任何帮助 颇有种脱了裤子放屁的感觉 但也不失为一种解决方案 (不推荐)

  using (SqlConnection conn = new SqlConnection(connectionString))

  

  conn Open();

  SqlCommand m = new SqlCommand();

  m Connection = conn;

  //使用exec动态执行SQL  //实际执行的查询计划为(@UserID varchar(max))select * from Users(nolock) where UserID in ( )  //不是预期的(@UserID varchar(max))exec( select * from Users(nolock) where UserID in ( +@UserID+ ) ) m CommandText = "exec( select * from Users(nolock) where UserID in ( +@UserID+ ) )";

  m Parameters Add(new SqlParameter("@UserID" SqlDbType VarChar ) Value = " " );

  m ExecuteNonQuery();

  

  方案 为where in的每一个参数生成一个参数 写法上比较麻烦些 传输的参数个数有限制 最多 个 可以根据需要使用此方案 (推荐)

  using (SqlConnection conn = new SqlConnection(connectionString))

  

  conn Open();

  SqlCommand m = new SqlCommand();

  m Connection = conn;

  //为每一条数据添加一个参数

  m CommandText = "select * from Users(nolock) where UserID in (@UserID @UserId @UserID @UserID )";

  m Parameters AddRange(

  new SqlParameter[]

  

  new SqlParameter("@UserID " SqlDbType Int) Value =

  new SqlParameter("@UserID " SqlDbType Int) Value =

  new SqlParameter("@UserID " SqlDbType Int) Value =

  new SqlParameter("@UserID " SqlDbType Int) Value =

  );

  m ExecuteNonQuery();

  

  方案 使用临时表实现 写法实现上比较繁琐些 可以根据需要写个通用的where in临时表查询的方法 以供不时之需 个人比较推崇这种写法 能够使查询计划得到复用而且对索引也能有效的利用 不过由于需要创建临时表 会带来额外的IO开销 若查询频率很高 每次的数据不多时还是建议使用方案 若查询数据条数较多 尤其是上千条甚至上万条时 强烈建议使用此方案 可以带来巨大的性能提升 (强烈推荐)

  using (SqlConnection conn = new SqlConnection(connectionString))

  

  conn Open();

  SqlCommand m = new SqlCommand();

  m Connection = conn;

  string sql = @"

  declare @Temp_Variable varchar(max)

  create table #Temp_Table(Item varchar(max))

  while(LEN(@Temp_Array) > )

  begin

  if(CHARINDEX( @Temp_Array) = )

  begin

  set @Temp_Variable = @Temp_Array

  set @Temp_Array =

  end

  else

  begin

  set @Temp_Variable = LEFT(@Temp_Array CHARINDEX( @Temp_Array) )

  set @Temp_Array = RIGHT(@Temp_Array LEN(@Temp_Array) LEN(@Temp_Variable) )

  end

  insert into #Temp_Table(Item) values(@Temp_Variable)

  end

  select * from Users(nolock) where exists(select from #Temp_Table(nolock) where #Temp_Table Item=Users UserID)

  drop table #Temp_Table";

  m CommandText = sql;

  m Parameters Add(new SqlParameter("@Temp_Array" SqlDbType VarChar ) Value = " " );

  m ExecuteNonQuery();

  

  like参数化查询

  like查询根据个人习惯将通配符写到参数值中或在SQL拼接都可 两种方法执行效果一样 在此不在详述

  using (SqlConnection conn = new SqlConnection(connectionString))

  

  conn Open();

  SqlCommand m = new SqlCommand();

  m Connection = conn;

  //将 % 写到参数值中

  m CommandText = "select * from Users(nolock) where UserName like @UserName";

  m Parameters Add(new SqlParameter("@UserName" SqlDbType VarChar ) Value = "rabbit%" );

  m ExecuteNonQuery();

  

  using (SqlConnection conn = new SqlConnection(connectionString))

  

  conn Open();

  SqlCommand m = new SqlCommand();

  m Connection = conn;

  //SQL中拼接 %

  m CommandText = "select * from Users(nolock) where UserName like @UserName+ % ";

  m Parameters Add(new SqlParameter("@UserName" SqlDbType VarChar ) Value = "rabbit%" );

  m ExecuteNonQuery();

  

cha138/Article/program/SQLServer/201311/22280

相关参考

知识大全 sql server 2008亿万数据性能优化

  根据设计惯例查询的时候主子表通过关键词字段关联查询查询语句如下  selecttopawordaqueryurlairankatitleabaiduurlaitrafficaitrafficbib

知识大全 Web环境下的SQL Server数据备份与恢复[2]

Web环境下的SQLServer数据备份与恢复[2]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

知识大全 Web环境下的SQL Server数据备份与恢复[1]

Web环境下的SQLServer数据备份与恢复[1]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

知识大全 Sql Server 数据库表查询结果导出为excel文件

SqlServer数据库表查询结果导出为excel文件  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧

知识大全 在SQL Server 2000查询分析器里面收缩数据库日志

在SQLServer2000查询分析器里面收缩数据库日志  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下

知识大全 查询参数提高SQL语句的利用率

查询参数提高SQL语句的利用率  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  有时候数据库管理员

知识大全 SQL Server 2012迎战大数据

SQLServer2012迎战大数据  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!微软日前发布了S

知识大全 并行查询让SQL Server加速运行

并行查询让SQLServer加速运行  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  并行查询其优

知识大全 用SQL Server查询累计值

用SQLServer查询累计值  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  有这样一个要求它要

知识大全 用并行查询让SQL Server加速运行

用并行查询让SQLServer加速运行  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  并行查询其