博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Sql Server如何去掉IN查询

Posted on 2011-10-11 13:26  Honor  阅读(441)  评论(0)    收藏  举报

IN的危害由于in不支持变量绑定。所以,in语句必须使用“$变量$”来描述,为sql注入埋下了隐患。同样,sql语句解析和执行计划不能复用。由于执行计划不能复用,当发生很多次IN不同内容调用的时候,会把以前的经常复用的sql语句的执行计划cache给挤出去。如何消灭IN把in变成参数。固定参数的长度。步骤创建函数 SplitInt.sql和SplitStr.sql  效果如下:


组织sql

老格式:
select t2.* from   lily_project T2 where t2.projectname in ('亚洲一号','测试')
 新格式:
 select t2.* from SplitStr('亚洲一号,测试') T1 , lily_project T2
where t1.value = t2.projectname

老格式:
select t2.* from  lily_project T2 where  t2.project_id in (67,2,3)

新格式:

select t2.* from SplitInt('67,2,3') T1 , lily_project T2
where t1.value = t2.project_id

配置定长参数,由于Sql Server对于不同的参数长度,会产生不过的执行路径的KEY。所以,必须要统一参数长度。这个长度可以指定为1,输入值超过1,不受影响。ibatis的inlineParameter无法设置参数长度,必须依靠ParameterMap来设置。所以,最终效果如下:

    <parameterMap id="testjoin" class="string">
        <parameter property="value" dbtype="varchar" size="1"/>
    </parameterMap>

    <select id="testJoinIn" parameterMap="testjoin" resultClass="project">        
        select t2.* from SplitInt(?) T1 , lily_project T2 where t1.value = t2.project_id
    </select>


 效果

         经过测试,使用上面的语句能提高20%的效率。另外,单个语句执行无提高效果。

其它

        受到启发,其它所有调用的时候。如果参数中有字符串的时候,一定要使用parameterMap形式,并且定义paramter的size

 

********************************************************************************************************************************************************
CREATE FUNCTION [dbo].[SplitInt]
(
 @SplitString varchar(8000)
)
RETURNS @SplitIntTable TABLE
(
 [value] int
)
AS
BEGIN
    DECLARE @Separator varchar(2);

    DECLARE @CurrentIndex int;
    DECLARE @NextIndex int;
    DECLARE @ReturnText int;
    SELECT @CurrentIndex=1;
    SELECT @Separator = ',';

    WHILE(@CurrentIndex<=len(@SplitString))
    BEGIN
        SELECT @NextIndex=charindex(@Separator,@SplitString,@CurrentIndex);
        IF(@NextIndex=0 OR @NextIndex IS NULL)
            SELECT @NextIndex=len(@SplitString)+1;
       
        SELECT @ReturnText=cast(substring(@SplitString,@CurrentIndex,@NextIndex-@CurrentIndex) as int);

        INSERT INTO @SplitIntTable([value])
        VALUES(@ReturnText);
       
        SELECT @CurrentIndex=@NextIndex+1;
    END
    RETURN;
END

********************************************************************************************************************************************************


CREATE  FUNCTION [dbo].[SplitStr]
(
 @SplitString varchar(8000)
)
RETURNS @SplitStringsTable TABLE
(
 [value] varchar(8000)
)
AS
BEGIN

    DECLARE @Separator varchar(2);

    DECLARE @CurrentIndex int;
    DECLARE @NextIndex int;
    DECLARE @ReturnText varchar(8000);-- nvarchar(4000)
    SELECT @CurrentIndex=1;
    SELECT @Separator = ',';
    WHILE(@CurrentIndex<=len(@SplitString))
    BEGIN
        SELECT @NextIndex=charindex(@Separator,@SplitString,@CurrentIndex);
        IF(@NextIndex=0 OR @NextIndex IS NULL)
            SELECT @NextIndex=len(@SplitString)+1;
       
        SELECT @ReturnText=substring(@SplitString,@CurrentIndex,@NextIndex-@CurrentIndex);

        INSERT INTO @SplitStringsTable([value])
        VALUES(@ReturnText);
       
        SELECT @CurrentIndex=@NextIndex+1;
    END
    RETURN;
END