`
leiliang
  • 浏览: 46055 次
社区版块
存档分类
最新评论

SQL Server中存储过程比直接运行SQL语句慢的原因

阅读更多
在很多的资料中都描述说SQLSERVER的存储过程较普通的SQL语句有以下优点:

<!--[if !supportLists]-->1.       <!--[endif]-->存储过程只在创造时进行编译即可,以后每次执行存储过程都不需再重新编译,而我们通常使用的SQL语句每执行一次就编译一次,所以使用存储过程可提高数据库执行速度。
<!--[if !supportLists]-->2.       <!--[endif]-->经常会遇到复杂的业务逻辑和对数据库的操作,这个时候就会用SP来封装数据库操作。当对数据库进行复杂操作时(如对多个表进行 Update,Insert,Query,Delete时),可将此复杂操作用存储过程封装起来与数据库提供的事务处理结合一起使用。可以极大的提高数据 库的使用效率,减少程序的执行时间,这一点在较大数据量的数据库的操作中是非常重要的。在代码上看,SQL语句和程序代码语句的分离,可以提高程序代码的 可读性。
<!--[if !supportLists]-->3.       <!--[endif]-->存储过程可以设置参数,可以根据传入参数的不同重复使用同一个存储过程,从而高效的提高代码的优化率和可读性。
<!--[if !supportLists]-->4.       <!--[endif]-->安全性高,可设定只有某此用户才具有对指定存储过程的使用权存储过程的种类:
<!--[if !supportLists]-->A.       <!--[endif]-->系统存储过程:以sp_开头,用来进行系统的各项设定.取得信息.相关管理工作,如 sp_help就是取得指定对象的相关信息。
<!--[if !supportLists]-->B.       <!--[endif]-->扩展存储过程 以XP_开头,用来调用操作系统提供的功能
exec master..xp_cmdshell 'ping 10.8.16.1'
<!--[if !supportLists]-->C.       <!--[endif]-->用户自定义的存储过程,这是我们所指的存储过程常用格式
    模版:Create procedure procedue_name [@parameter data_type][output]
    [with]{recompile|encryption} as sql_statement
    解释:output:表示此参数是可传回的
with {recompile|encryption} recompile:表示每次执行此存储过程时都重新编译一次;encryption:所创建的存储过程的内容会被加密。

   但是最近我们项目组中有人写了一个存储过程,其计算时间为1个小时47分钟,而有的时候运行时间都超过了两个小时,同事描述说如果将存储过程中的语句拿出来直接运行也就10分钟左右就运行完毕,我没当回事,但是今天我自己写的存储过程也遇到了这个问题,在查找资料后原因终于找到了原因,原来是Parameter sniffing问题。
    下面看我是如何将运行一个小时以上的存储过程优化成在一分钟之内完成的:
原存储过程
CREATE PROCEDURE [dbo].[pro_ImAnalysis_daily]
@THEDATE VARCHAR(30)
AS
BEGIN
    IF @THEDATE IS NULL
    BEGIN
       SET @THEDATE=CONVERT(VARCHAR(30),GETDATE()-1,112);
    END


    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
每日执行:exec pro_ImAnalysis_daily @thedate=null
耗时:1小时47分~2小时13分
经过查找资料,原因如下(由于源文是一篇英文,有些地方写的我不是特别清楚,原文见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”问题:
<!--[if !supportLists]-->(1)<!--[endif]-->通过使用declare声明的变量来代替参数:使用set @variable=@thedate的方式,将出现@thedate的sql语句全部用@variable来代替。
<!--[if !supportLists]-->(2) <!--[endif]-->将受影响的sql语句隐藏起来,比如:
<!--[if !supportLists]-->a)      <!--[endif]-->将受影响的sql语句放到某个子存储过程中,比如我们在@thedate设置成为今天后再调用一个字存储过程将@thedate作为参数传入就可以了。
<!--[if !supportLists]-->b)      <!--[endif]-->使用sp_executesql来执行受影响的sql。执行计划不会被执行,除非sp_executesql语句执行完。
<!--[if !supportLists]-->c)      <!--[endif]-->使用动态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

测试执行速度为10分钟,我又检查了一下这个SQL,发现这个SQL有问题,这个SQL使用了not exists,在一个大表里面使用not exists是不太明智的,所以,我又对这个sql进行了改进,改成如下:
    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 @thedate as thedate,
           count(distinct case when today>0 then userid else null end) as alluser,
           count(distinct case when dates=0 then userid else null end) as newuser
    from
    (
       select userid,
              count(CASE WHEN thedate>=@thedate then null else thedate end) as dates,
              count(case when thedate=@thedate then thedate else null end) as today
       from   FACT
       group by userid
    )as fact
GO
测试结果为30ms以下。
分享到:
评论

相关推荐

    SqlServer存储过程及调试指南

    1. 存储过程概念:存储过程是一组为完成特定功能的SQL语句集,这些语句经过编译后存储在数据库中,供用户通过指定存储过程名和参数(如有)来执行。存储过程被称作数据库中的重要对象,对于设计良好的数据库应用程序...

    在VB6.0中调用SQL Server的存储过程.pdf

    在SQL Server中,存储过程可以通过Transact-SQL语句CREATE PROCEDURE创建。存储过程的定义包含两个主要组成部分:过程名称及其参数的说明,以及过程的主体。过程名称及其参数的说明中,过程名必须符合标识符规则,...

    SQL_Server存储过程调试指南

    资源名称:SQL_Server存储过程调试指南内容简介: 存储过程( Stored Procedure)是一组为了完成特定功能的 SQL 语句集,经编译后存储在数据库中。用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来...

    sql server 2008 存储过程与储发器 详解 书籍

    首先,存储过程是预编译的SQL语句集合,可以看作是数据库中的可执行程序。在SQL Server 2008中,存储过程分为系统存储过程、扩展存储过程和用户自定义存储过程。它们的优点包括提高性能(因为SQL语句预先编译)、...

    Sql Server 存储过程的导出导入.doc

    在SQL Server中,存储过程是一种预编译的SQL语句集合,它允许开发人员封装一组复杂的操作,并在需要时重复调用。存储过程对于数据库管理、数据处理和性能优化具有重要意义。本文主要介绍如何在SQL Server中导出和...

    oracle到sqlserver存储过程语法转换

    ### Oracle到SQL Server存储过程语法转换详解 在数据库迁移项目中,从Oracle迁移到SQL Server是一种常见的场景。本文旨在提供一份详细的指南,帮助开发者更好地理解这两种数据库系统在存储过程方面的语法差异,并...

    针对sqlserver 2008 存储过程通过With Encryption加密方式的解密

    SQL Server 2008 存储过程中使用 With Encryption 加密方式可以对存储过程进行加密保护,以防止未经授权的访问和修改。但是,在某些情况下,我们需要对加密的存储过程进行解密,以便进行维护、升级或 troubleshoot。...

    SQL server存储过程习题,SQL触发器习题.rar

    6. **动态SQL**:存储过程中可以嵌入动态SQL语句,根据需要在运行时生成并执行SQL。 7. **返回值**:存储过程可以设置返回值,用`RETURN`语句传递结果给调用者。 **SQL触发器**: 1. **定义**:触发器是一种特殊的...

    SQL Server存储过程基本语法

    以上内容主要介绍了 SQL Server 中存储过程中的一些基本语法和操作方法,包括变量定义及赋值、表和临时表的操作、循环以及条件语句等,这些知识点对于理解和使用 SQL Server 存储过程至关重要。

    sql分页 sqlserver中存储过程分页

    存储过程是一种预先编译好的 SQL 代码块,存储在 SQL Server 数据库中。使用存储过程进行分页查询的好处包括:提高执行效率、增强代码复用性以及提供更好的安全性等。 #### 示例存储过程分析 下面将详细分析给定的...

    执行Sqlserver存储过程返回DataSet

    **存储过程(Stored Procedure)**:是一种预编译的SQL代码,可以被多次调用并在服务器上执行,提高了SQL语句的执行效率和重用性。它可以在数据库中定义并保存,之后可以在应用程序中通过简单的调用来执行复杂的逻辑...

    SQLServer存储过程中事务的使用方法

    存储过程是一组预编译的SQL语句,可以在数据库中被多次调用,提高了效率并降低了网络流量。本篇将详细介绍如何在SQL Server存储过程中使用事务。 首先,事务有四个基本特性,即ACID(原子性、一致性、隔离性和持久...

    SQL Server存储过程对比工具

    首先,存储过程是SQL Server数据库中预编译的SQL语句集合,通常用于执行复杂的业务逻辑或提高数据访问效率。它们可以接受参数、返回结果集,甚至包含控制流程语句,如IF-ELSE、WHILE等。对比存储过程对于多环境部署...

    20120330_Linux下用freetds执行SqlServer的sql语句和存储过程1

    本文将详细介绍如何使用 FreeTDS 在 Linux 系统下执行 Sql Server 的 sql 语句和存储过程,包括直接执行 sql 语句、不带参数的存储过程和带参数的存储过程。 一、包含头文件 在使用 FreeTDS 之前,需要包含相应的...

    sqlserver存储过程函数加解密保好用工具dbForge SQL Decryptor v3.1.24

    存储过程是一组为了完成特定功能的SQL语句集,它经过编译和优化后存储在数据库中,用户可以通过调用来执行这些预编译的SQL语句。存储过程可以包含复杂的业务逻辑,提高执行效率,并且可以被多次调用。而函数则是一类...

    SQLServer 2000存储过程手册

    10. **动态SQL**:在存储过程中,可以使用字符串拼接生成动态SQL语句,然后通过sp_executesql执行,这种方法在处理灵活的查询需求时非常有用,但要注意防止SQL注入攻击。 11. **存储过程的版本控制**:对于大型项目...

    sql Server 2005 存储过程视频

    存储过程是SQL Server 2005中的一个核心特性,是预编译的SQL语句集合,可以理解为数据库中的可执行程序。本视频教程针对存储过程这一主题,对初学者提供了宝贵的教育资源。 存储过程的优势在于: 1. **性能优化**...

    最简单的SQL Server数据库存储过程分页

    本文介绍一种简单且高效的SQL Server存储过程实现分页的方法,这种方法仅需提供SQL语句、每页的记录数以及当前页数即可快速完成分页操作。 #### SQL Server存储过程分页原理 在SQL Server中,通过存储过程实现分页...

Global site tag (gtag.js) - Google Analytics