zoukankan      html  css  js  c++  java
  • SQL Server中存储过程比直接运行SQL语句慢的原因

     

    经过查找资料,原因如下(由于源文是一篇英文,有些地方写的我不是特别清楚,原文见http://groups.google.com/group/microsoft.public.sqlserver.server/msg/ad37d8aec76e2b8f?hl=en&lr=&ie=UTF-8&oe=UTF-8):
        SQL Server中有一个叫做 “Parameter sniffing”的特性。SQL Server在存储过程执行之前都会制定一个执行计划。在上面的例子中,SQL在编译的时候并不知道@thedate的值是多少,所以它在执行执行计划的时候就要进行大量的猜测。假设传递给@thedate的参数大部分都是非空字符串,而FACT表中有40%的thedate字段都是null,那么SQL Server就会选择全表扫描而不是索引扫描来对参数@thedate制定执行计划。全表扫描是在参数为空或为0的时候最好的执行计划。但是全表扫描严重影响了性能。
        假设你第一次使用了Exec pro_ImAnalysis_daily @thedate=’20080312’那么SQL Server就会使用20080312这个值作为下次参数@thedate的执行计划的参考值,而不会进行全表扫描了,但是如果使用@thedate=null,则下次执行计划就要根据全表扫描进行了。
        有两种方式能够避免出现“Parameter sniffing”问题:
    <!--(1)通过使用declare声明的变量来代替参数:使用set @variable=@thedate的方式,将出现@thedatesql语句全部用@variable来代替。
    <!--(2) 将受影响的sql语句隐藏起来,比如:
    <!-- a)      将受影响的sql语句放到某个子存储过程中,比如我们在@thedate设置成为今天后再调用一个字存储过程将@thedate作为参数传入就可以了。
    <!-- b)      使用sp_executesql来执行受影响的sql。执行计划不会被执行,除非sp_executesql语句执行完。
    <!-- c)      使用动态sql”EXEC(@sql)”来执行受影响的sql
    采用(1)的方法改造例子中的存储过程,如下:

       
    代码
    ALTER PROCEDURE [dbo].[pro_ImAnalysis_daily]
    @var_thedate VARCHAR(30)

    AS
    BEGIN
    declare @THEDATE VARCHAR(30)
    IF @var_thedate IS NULL
    BEGIN
    SET @var_thedate=CONVERT(VARCHAR(30),GETDATE()-1,112);
    END


    SET @THEDATE=@var_thedate;
    DELETE FROM RPT_IM_USERINFO_DAILY WHERE THEDATE=@THEDATE;

    INSERT RPT_IM_USERINFO_DAILY (THEDATE,ALLUSER,NEWUSER)
    SELECT AA.THEDATE,ALLUSER,NEWUSER
    FROM
    ( (
    SELECT THEDATE,COUNT(DISTINCT USERID) ALLUSER
    FROM FACT
    WHERE THEDATE=@THEDATE
    GROUP BY THEDATE
    ) AA
    LEFT JOIN
    (
    SELECT THEDATE,COUNT(DISTINCT USERID) NEWUSER
    FROM FACT T1
    WHERE NOT EXISTS(
    SELECT 1
    FROM FACT T2
    WHERE T2.THEDATE<@THEDATE
    AND T1.USERID=T2.USERID)
    AND T1.THEDATE=@THEDATE
    GROUP BY THEDATE
    ) BB
    ON AA.THEDATE=BB.THEDATE);
    GO

    此文应用原地址为:http://sumandeng.spaces.live.com/blog/cns!54107D687F0B8E2F!916.trak

  • 相关阅读:
    dblink密码
    Select .. into .. 和 OCIBindByName
    在网上东逛西逛看到这篇文章,鼻子有点酸。
    奇怪的LINUX系统时间问题
    综合练习:简单日历
    15位到18位身份证的升级计算
    进入面向对象的世界:类就是代码,对象是内存。
    关于数据类型转换的补充知识
    数学函数
    抽象类和密封类
  • 原文地址:https://www.cnblogs.com/nikyxxx/p/1687101.html
Copyright © 2011-2022 走看看