Performance 静态查询与存储过程的性能问题
我有两个几乎相同的查询,第一个是带有变量的静态查询,第二个是带有输入参数的存储过程 静态查询Performance 静态查询与存储过程的性能问题,performance,sql-server-2008,stored-procedures,Performance,Sql Server 2008,Stored Procedures,我有两个几乎相同的查询,第一个是带有变量的静态查询,第二个是带有输入参数的存储过程 静态查询 DECLARE @GLNumber INT = 1043 DECLARE @StartDate DATE = '1/1/2015' DECLARE @EndDate DATE = '4/20/2015' SELECT T1.EMPLOYEE AS [Empolyee Number], T2.LAST_NAME AS [Last N
DECLARE @GLNumber INT = 1043
DECLARE @StartDate DATE = '1/1/2015'
DECLARE @EndDate DATE = '4/20/2015'
SELECT
T1.EMPLOYEE AS [Empolyee Number],
T2.LAST_NAME AS [Last Name],
T2.FIRST_NAME AS [First Name],
T1.DST_ACCT_UNIT AS [Distribution Account Unit],
T3.DESCRIPTION,
SUM(T1.WAGE_AMOUNT) AS [Wage Amount]
FROM
JOBCODE T3,
EMPLOYEE T2 LEFT OUTER JOIN
PRTIME T1 ON
T2.COMPANY = T1.COMPANY and
T2.EMPLOYEE = T1.EMPLOYEE
WHERE
T1.DIST_COMPANY = @GLNumber and
CONVERT(DATE, TR_DATE, 101) BETWEEN @StartDate AND @EndDate AND
T1.PAY_SUM_GRP in ('TPC', 'TDS') and
T2.JOB_CODE = T3.JOB_CODE and
T2.COMPANY = T3.COMPANY
GROUP BY
T1.EMPLOYEE,
T2.LAST_NAME,
T2.FIRST_NAME,
T1.DST_ACCT_UNIT,
T3.DESCRIPTION
存储过程
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[MySproc]
(
@GLNumber INT = NULL,
@StartDate DATE = NULL,
@EndDate DATE = NULL
)
AS
BEGIN
SET NOCOUNT ON;
SELECT
T1.EMPLOYEE AS [Empolyee Number],
T2.LAST_NAME AS [Last Name],
T2.FIRST_NAME AS [First Name],
T1.DST_ACCT_UNIT AS [Distribution Account Unit],
T3.DESCRIPTION,
SUM(T1.WAGE_AMOUNT) AS [Wage Amount]
FROM
JOBCODE T3,
EMPLOYEE T2 LEFT OUTER JOIN
PRTIME T1 ON
T2.COMPANY = T1.COMPANY and
T2.EMPLOYEE = T1.EMPLOYEE
WHERE
T1.DIST_COMPANY = @GLNumber and
CONVERT(DATE, TR_DATE, 101) BETWEEN @StartDate AND @EndDate AND
T1.PAY_SUM_GRP in ('TPC', 'TDS') and
T2.JOB_CODE = T3.JOB_CODE and
T2.COMPANY = T3.COMPANY
GROUP BY
T1.EMPLOYEE,
T2.LAST_NAME,
T2.FIRST_NAME,
T1.DST_ACCT_UNIT,
T3.DESCRIPTION
END
我确信您可以看到,两个查询之间的最大区别在于第一个查询使用声明的变量,而第二个查询使用输入参数
两个查询返回相同、正确的结果。但是,在我的系统上运行静态查询只需不到1秒,而从我的系统执行存储过程则需要3 1/2分钟以上
我不明白为什么静态查询和存储过程之间的执行时间会有如此大的差异(我希望执行时间是相似的,尤其是在这样一个简单的查询上)
我在效率上出现这种差异的潜在原因是什么?
DECLARE @GLNumber INT = 1043
DECLARE @StartDate DATE = '1/1/2015'
DECLARE @EndDate DATE = '4/20/2015'
SELECT
T1.EMPLOYEE AS [Empolyee Number],
T2.LAST_NAME AS [Last Name],
T2.FIRST_NAME AS [First Name],
T1.DST_ACCT_UNIT AS [Distribution Account Unit],
T3.DESCRIPTION,
SUM(T1.WAGE_AMOUNT) AS [Wage Amount]
FROM
JOBCODE T3,
EMPLOYEE T2 LEFT OUTER JOIN
PRTIME T1 ON
T2.COMPANY = T1.COMPANY and
T2.EMPLOYEE = T1.EMPLOYEE
WHERE
T1.DIST_COMPANY = @GLNumber and
CONVERT(DATE, TR_DATE, 101) BETWEEN @StartDate AND @EndDate AND
T1.PAY_SUM_GRP in ('TPC', 'TDS') and
T2.JOB_CODE = T3.JOB_CODE and
T2.COMPANY = T3.COMPANY
GROUP BY
T1.EMPLOYEE,
T2.LAST_NAME,
T2.FIRST_NAME,
T1.DST_ACCT_UNIT,
T3.DESCRIPTION
我知道存储过程通常不会提供相对于静态查询的性能优势,但是,与静态查询相比,我从未体验过存储过程的性能如此之差
有没有办法纠正此性能问题?我在SQLServer2008R2,SP1上操作
澄清
运行存储过程时,我传入的参数与静态查询中使用的参数相同。在静态版本中,StartDate和EndDate的变量已赋值 在SP版本中,它们为空
SP版本必须在整个数据日期范围内运行,而静态版本只能在相关的日期范围内运行(可能使用索引)。好的,因此我可以通过更新查询中的
FROM
和WHERE
子句来解决这个问题。本质上,由于某种原因,存储过程不喜欢使用逗号代替内部联接。。。在
上。这使存储过程上的执行时间降低到不到一秒
最后确定的程序如下:
ALTER PROCEDURE [dbo].[rptTipReport_ByCompany]
(
@GLNumber INT = NULL,
@StartDate DATE = NULL,
@EndDate DATE = NULL
)
AS
BEGIN
SET NOCOUNT ON;
SELECT
T1.EMPLOYEE AS [Empolyee Number],
T2.LAST_NAME AS [Last Name],
T2.FIRST_NAME AS [First Name],
T1.DST_ACCT_UNIT AS [Distribution Account Unit],
T3.DESCRIPTION,
SUM(T1.WAGE_AMOUNT) AS [Wage Amount]
FROM
PROD90.dbo.PRTIME T1
LEFT JOIN PROD90.dbo.EMPLOYEE T2 on T1.EMPLOYEE = T2.EMPLOYEE
INNER JOIN PROD90.dbo.JOBCODE T3 on T2.JOB_CODE = T3.JOB_CODE
WHERE
T1.DIST_COMPANY = @GLNumber and
CONVERT(DATE, TR_DATE, 101) BETWEEN @StartDate AND @EndDate AND
T1.PAY_SUM_GRP in ('TPC', 'TDS')
GROUP BY
T1.EMPLOYEE,
T2.LAST_NAME,
T2.FIRST_NAME,
T1.DST_ACCT_UNIT,
T3.DESCRIPTION
END
这些是默认值。假设OP正在从外部将相同的实际参数值传递到proc中,否则这个问题将毫无意义。是的,我正在将相同的参数传递到存储过程中,就像在静态查询中一样。您可以使用一些示例数据创建一个`以便我们可以查看架构、索引和代码。即使示例数据相对较小,SP的执行时间也可能较慢,多亏了Martin,我尝试将带有重新编译的
添加到过程中,但没有效果。我在表上另外尝试了使用(NOLOCK)
进行,但同样没有影响。使用(NOLOCK)
对参数嗅探没有影响。尝试将选项(重新编译)
添加到查询中。虽然嗅探的参数值也可能与您正在执行的参数值相同,并且统计信息需要更新。谢谢,选项(重新编译)
和更新数据库统计信息都没有帮助,但是,我发现通过对FROM/WHERE语句重新排序,与静态查询一样,我能够在不到1秒的时间内从存储过程中获得正确的结果。我将更新后的查询作为解决方案发布。