京公网安备 11010802034615号
经营许可证编号:京B2-20210330
在很多的资料中都描述说SQLSERVER的存储过程较普通的SQL语句有以下优点:
存储过程只在创造时进行编译即可,以后每次执行存储过程都不需再重新编译,而我们通常使用的SQL语句每执行一次就编译一次,所以使用存储过程可提高数据库执行速度。
经常会遇到复杂的业务逻辑和对数据库的操作,这个时候就会用SP来封装数据库操作。当对数据库进行复杂操作时(如对多个表进行 Update,Insert,Query,Delete时),可将此复杂操作用存储过程封装起来与数据库提供的事务处理结合一起使用。可以极大的提高数据 库的使用效率,减少程序的执行时间,这一点在较大数据量的数据库的操作中是非常重要的。在代码上看,SQL语句和程序代码语句的分离,可以提高程序代码的 可读性。
存储过程可以设置参数,可以根据传入参数的不同重复使用同一个存储过程,从而高效的提高代码的优化率和可读性。
安全性高,可设定只有某此用户才具有对指定存储过程的使用权存储过程的种类:
系统存储过程:以sp_开头,用来进行系统的各项设定.取得信息.相关管理工作,如 sp_help就是取得指定对象的相关信息。
扩展存储过程 以XP_开头,用来调用操作系统提供的功能
exec master..xp_cmdshell ‘ping 10.8.16.1’
用户自定义的存储过程,这是我们所指的存储过程常用格式
模版: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”问题:
(1)通过使用declare声明的变量来代替参数:使用set @variable=@thedate的方式,将出现@thedate的sql语句全部用@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
测试执行速度为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以下。
数据分析咨询请扫描二维码
若不方便扫码,搜微信号:CDAshujufenxi
主讲人简介 张冲,海归统计学硕士,CDA 认证数据分析师,前云南白药集团资深数据分析师,自媒体 Python 讲师,全网课程播放量破 ...
2026-04-10在数据可视化与业务分析中,同比分析是衡量业务发展趋势、识别周期波动的核心手段,其核心逻辑是将当前周期数据与上年同期数据进 ...
2026-04-10在机器学习模型的落地应用中,预测精度并非衡量模型可靠性的唯一标准,不确定性分析同样不可或缺。尤其是在医疗诊断、自动驾驶、 ...
2026-04-10数据本身是沉默的,唯有通过有效的呈现方式,才能让其背后的规律、趋势与价值被看见、被理解、被运用。统计制图(数据可视化)作 ...
2026-04-10在全球化深度发展的今天,跨文化传播已成为连接不同文明、促进多元共生的核心纽带,其研究核心围绕“信息传递、文化解读、意义建 ...
2026-04-09在数据可视化领域,折线图是展示时序数据、趋势变化的核心图表类型之一,其简洁的线条的能够清晰呈现数据的起伏规律。Python ECh ...
2026-04-09在数据驱动的时代,数据分析早已不是“凭经验、靠感觉”的零散操作,而是一套具备固定逻辑、标准化流程的系统方法——这就是数据 ...
2026-04-09长短期记忆网络(LSTM)作为循环神经网络(RNN)的重要改进模型,凭借其独特的门控机制(遗忘门、输入门、输出门),有效解决了 ...
2026-04-08在数据分析全流程中,数据质量是决定分析结论可靠性的核心前提,而异常值作为数据集中的“异类”,往往会干扰统计检验、模型训练 ...
2026-04-08在数字经济飞速发展的今天,数据已渗透到各行各业的核心场景,成为解读趋势、优化决策、创造价值的核心载体。而数据分析,作为挖 ...
2026-04-08在数据分析全流程中,数据处理是基础,图形可视化是核心呈现手段——前者负责将杂乱无章的原始数据转化为干净、规范、可分析的格 ...
2026-04-07在数据分析与统计推断中,p值是衡量假设检验结果显著性的核心指标,其本质是在原假设(通常为“无效应”“无差异”)成立的前提 ...
2026-04-07在数字经济深度渗透的今天,数据已成为企业生存发展的核心资产,企业的竞争本质已转变为数据利用能力的竞争。然而,大量来自生产 ...
2026-04-07Python凭借简洁的语法、丰富的生态库,成为算法开发、数据处理、机器学习等领域的首选语言。但受限于动态类型、解释性执行的特性 ...
2026-04-03在深度学习神经网络中,卷积操作是实现数据特征提取的核心引擎,更是让模型“看懂”数据、“解读”数据的关键所在。不同于传统机 ...
2026-04-03当数字化转型从企业的“战略口号”落地为“生存之战”,越来越多的企业意识到,转型的核心并非技术的堆砌,而是数据价值的深度挖 ...
2026-04-03在日常办公数据分析中,数据透视表凭借高效的汇总、分组功能,成为Excel、WPS等办公软件中最常用的数据分析工具之一。其中,“计 ...
2026-04-02在数字化交互的全场景中,用户的每一次操作都在生成动态的行为轨迹——电商用户的“浏览商品→点击详情→加入购物车”,内容APP ...
2026-04-02在数字化转型深度推进的今天,企业数据已成为驱动业务增长、构建核心竞争力的战略资产,而数据安全则是守护这份资产的“生命线” ...
2026-04-02在数据驱动决策的浪潮中,数据挖掘与数据分析是两个高频出现且极易被混淆的概念。有人将二者等同看待,认为“做数据分析就是做数 ...
2026-04-01