一方面需要处理转移符 , 另一方面需要要防止SQL注入
其二 , 参数不同就必须重新编译
这种拼凑SQL的方式 , 如果每次查询的参数不同 , 拼凑出来的SQL字符串也不一样 ,
如果熟悉SQL Server的同学一定知道 , 只要你执行的SQL文本不一样 ,
比如
第一次是执行查询 *** where CustomerId = 'C88' ,
第二次是执行查询 *** where CustomerId = 'C99' , 因为两次执行的SQL文本不同
每次执行之前必然需要对其进行编译 , 编译的话就需要CPU , 内存资源
如果存在大批量的SQL编译 , 无疑要消耗更多的CPU资源(当然也需要一些内存资源)
第二种常见的写法:对所有查询条件用OR的方式加在where条件中 , 非常不推荐
create proc pr_getOrederInfo_2(@p_OrderNumberint,@p_CustomerIdvarchar(20) ,@p_OrderDateBegindatetime,@p_OrderDateEnddatetime)asbeginset nocount on;declare @strSql nvarchar(max);SELECT [id],[OrderNumber],[CustomerId],[OrderDate],[Remark]FROM [dbo].[SaleOrder]where 1=1and (@p_OrderNumber is nullor OrderNumber= @p_OrderNumber)and (@p_CustomerIdis nullor CustomerId= @p_CustomerId)/*这是另外一种类似的奇葩的写法,下面会重点关注andOrderNumber= ISNULL( @p_OrderNumber,OrderNumber)andCustomerId= ISNULL( @p_CustomerId,CustomerId)*/and (@p_OrderDateBegin is null or OrderDate>= @p_OrderDateBegin)and (@p_OrderDateEnd is nullor OrderDate<= @p_OrderDateEnd)end
首先看这种方式的执行结果 , 带入同样的参数 , 跟上面的结果一样 , 查询(结果)本身是没有任何问题的
文章插图
这种写法写起来避免了拼凑字符串的处理 , 看起来很简洁 , 写起来也很快 , 稀里哗啦一个存储过程就写好了 ,
发布到生产环境之后就相当于埋了一颗雷 , 随时引爆 。
因为一条低效而又频繁执行的SQL , 拖垮一台服务器也是司空见惯
但是呢 , 问题非常多 , 也非常非常不推荐 , 甚至比第一种方式更糟糕 。
分析一下这种处理方式的逻辑:
这种处理方式 , 因为不确定查询的时候到底有没有传入参数 , 也就是说不能确定某一个查询条件是否生效 ,
于是就采用类似 and (@p_OrderNumber is null or OrderNumber = @p_OrderNumber)这种方式 , 来处理参数 ,
这样的话
如果@p_OrderNumber为null , or的前者(@p_OrderNumber is null)成立 , 后者不成立 , 查询条件不生效
如果@p_OrderNumber为非null , or的后者(OrderNumber = @p_OrderNumber)成立而前者不成立 , 查询条件生效
总之来说 , 不管参数是否为空 , 都可以有效地拼凑到查询条件中去 。
避免了拼SQL字符串 , 既做到让参数非空的时候生效 , 有做到参数为空的时候不生效 , 看起来不错 , 是真的吗?
那么这种存储过程的有什么问题?
1 , 会抑制索引的情况
如图 , 带入参数值执行存储过程 , 先忽略另外三个查询字段 , 只传入@p_CustomerId参数 ,
相关查询列上(CustomerId)有索引 , 但是这里走的是CustomerId列上的Index Scan而非预期的Index Seek
文章插图
纠错:上面的一句话 , 使用参数做编译的时候 , 是知道参数的值的(只有使用本地变量的时候才不知道具体的参数值 , 直接使用参数确实是知道的) ,
编译也是根据具体的参数值来生成执行计划的 , 但是为什么即使知道具体的参数值的情况下 , 依然生成一个Index Scan的方式 , 而不是期望的Index Seek?
即便是存储过程在编译的时候知道了参数的值 , 为什么仍旧用不到索引?
还要从and (@p_CustomerId is null or CustomerId = @p_CustomerId)这种写法入手分析 。
即便是CustomerId列上有索引 ,
如果@p_CustomerId 参数非空 , 走索引Seek完全没有问题 。
如果@p_CustomerId 为null , 此时and (@p_CustomerId is null or CustomerId = @p_CustomerId)这个条件恒成立 , 如果再走索引Seek会出现什么结果?
推荐阅读
- 手把手教你构建一个简单的Eclipse RCP应用
- 浅析 Token 价值的意义及来源
- Linux 服务器安全加固 10 条建议
- 微头条一个月从0到2.7万,一天收入213元!淡泊飒姐是怎么做的?
- Linux之mv命令
- 女人春天吃什么可以排毒
- 大量收购红茶,红茶种类大全
- 红茶可以分为三大类,泡红茶种类
- 职业年金|公务员、事业编制人员职业年金可以领取多少年?可终身领取吗?
- 裳的读音shang还是chang?