这是我昨天问的一个问题的后续跟进:
Have you ever had SQL Server 2008 return a different result set than SQL Server 2000?
我最初认为存储过程在sql2000和sql2008上给出了不同的结果,但我已经做了相当多的缩小问题并消除了相当多的代码以使其归结为简单/可重现的问题。总结是,作为一个proc运行时,一段TSQL会返回一个不同的答案,即相同的代码运行只有TSQL,但仅在我的客户端服务器上运行,而不是在我的任何一个测试服务器上运行
当我运行此TSQL时:
DECLARE @PropertyID int
DECLARE @PortfolioID int
DECLARE @StartDate datetime
DECLARE @EndDate datetime
DECLARE @AcctMethod tinyint
SET @PropertyId=3555
--SET @PortfolioId = null
SET @StartDate= '3/1/2010'
SET @EndDate='2/28/2011'
SET @AcctMethod=1
DECLARE @ErrorMsg varchar(70)
DECLARE @ExclAcct tinyint
SET NOCOUNT ON
CREATE TABLE #IncomeStatement (
PropertyID int,
GLAccountID int,
SubTotalAccountID int,
Debits money,
Credits money,
YTDDebits money,
YTDCredits money,
PZDebits money,
PZCredits money,
AccountType tinyint
)
--Initialize Temporary Table
INSERT INTO #IncomeStatement(PropertyID, GLAccountID, SubTotalAccountID, AccountType, Debits, Credits, YTDDebits, YTDCredits, PZDebits, PZCredits)
SELECT PropertyID, ID, SubTotalAccountID, AccountType, 0, 0, 0, 0, 0, 0
FROM ChartOfAccounts
WHERE (PropertyID = @PropertyID OR @PropertyID Is Null)
AND (@PortfolioID is null OR PropertyID in (select PropertyID from PortfolioProperty where PortfolioID=@PortfolioID))
AND (Category > 3 or CashFlowCode <> 0)
--Period Activity
IF @AcctMethod = 1
SET @ExclAcct = 0
ELSE
SET @ExclAcct = 1
UPDATE Bal
SET
Debits = Debits + D.TotDebit,
Credits = Credits + D.TotCredit
FROM #IncomeStatement Bal
INNER JOIN (SELECT GLAccountID, Sum(Debit) AS TotDebit, Sum(Credit) AS TotCredit
FROM GLTransaction GT
WHERE (GT.PropertyID = @PropertyID OR @PropertyID Is Null)
AND AccountingMethod <> @ExclAcct
AND Posted = 1
AND TranDate >= @StartDate
AND TranDate <= @EndDate
GROUP BY GLAccountID) AS D
ON BAL.GLAccountID = D.GLAccountID
select * from #IncomeStatement where GLAccountID=11153
drop table #IncomeStatement
当我将上述代码转换为这样的存储过程时,我获得了124.27美元的借记金额:
CREATE Procedure [dbo].[sp_test]
@PropertyID int = Null,
@PortfolioID int = Null,
@StartDate datetime = Null,
@EndDate datetime = Null,
@AcctMethod tinyint = 1
AS
DECLARE @ErrorMsg varchar(70)
DECLARE @ExclAcct tinyint
SET NOCOUNT ON
CREATE TABLE #IncomeStatement (
PropertyID int,
GLAccountID int,
SubTotalAccountID int,
Debits money,
Credits money,
YTDDebits money,
YTDCredits money,
PZDebits money,
PZCredits money,
AccountType tinyint
)
--Initialize Temporary Table
INSERT INTO #IncomeStatement(PropertyID, GLAccountID, SubTotalAccountID, AccountType, Debits, Credits, YTDDebits, YTDCredits, PZDebits, PZCredits)
SELECT PropertyID, ID, SubTotalAccountID, AccountType, 0, 0, 0, 0, 0, 0
FROM ChartOfAccounts
WHERE (PropertyID = @PropertyID OR @PropertyID Is Null)
AND (@PortfolioID is null OR PropertyID in (select PropertyID from PortfolioProperty where PortfolioID=@PortfolioID))
AND (Category > 3 or CashFlowCode <> 0)
--Period Activity
IF @AcctMethod = 1
SET @ExclAcct = 0
ELSE
SET @ExclAcct = 1
UPDATE Bal
SET
Debits = Debits + D.TotDebit,
Credits = Credits + D.TotCredit
FROM #IncomeStatement Bal
INNER JOIN (SELECT GLAccountID, Sum(Debit) AS TotDebit, Sum(Credit) AS TotCredit
FROM GLTransaction GT
WHERE (GT.PropertyID = @PropertyID OR @PropertyID Is Null)
AND AccountingMethod <> @ExclAcct
AND Posted = 1
AND TranDate >= @StartDate
AND TranDate <= @EndDate
GROUP BY GLAccountID) AS D
ON BAL.GLAccountID = D.GLAccountID
select * from #IncomeStatement where GLAccountID=11153
drop table #IncomeStatement
然后执行它:
EXEC sp_test @PropertyID=3555, @StartDate='03/01/2010', @EndDate='02/28/2011'
我得到的借记金额为248.54美元,这应该是应该的两倍。
我真的很难过。更奇怪的是,如果我备份这个数据库,然后将其复制到运行sql2000的win2003服务器或运行SQL2008R2的win2008服务器,它在两种情况下都能正常工作。所以,似乎它是一个导致问题的服务器或数据库设置,但已经用完了要检查的东西 - 希望一组新的眼睛可以指出我遗漏的明显事物。
答案 0 :(得分:8)
好的,这是我的修复 - 它绝对不能解释原始问题,但这就是我所做的:
每当我遇到“参数嗅探”性能问题时,为了解决我为所有参数声明'local'变量,将这些参数分配给那些变量,然后在proc的其余部分中仅使用局部变量,像这样:
ALTER Procedure [dbo].[rptDateIncomeStatementPlusCash]
@PropertyID int = Null,
@PortfolioID int = Null,
@StartDate datetime = Null,
@EndDate datetime = Null,
@AcctMethod tinyint = 1
AS
DECLARE @xPropertyID int
DECLARE @xPortfolioID int
DECLARE @xStartDate datetime
DECLARE @xEndDate datetime
DECLARE @xAcctMethod tinyint
SET @xPropertyID= @PropertyId
SET @xPortfolioId = @PortfolioId
SET @xStartDate = @StartDate
SET @xEndDate = @EndDate
SET @xAcctMethod = @AcctMethod
相似之处在于,当参数嗅探是一个问题时,您可以通过MGMT工作室运行存储过程并获得比将其作为SQL运行更好的性能,并且更改(如上所述)通常会修复它。
在我的情况下,我发现直接TSQL与执行proc之间存在差异(尽管它与性能无关),我试了一下 - 并且预先确定它有效;我希望我有一个更好的解释,因为老实说,我发现在运行几乎相同的代码时,认为SQL服务器会出现不一致的结果是可怕的。
我确实找到this bulletin from MS关于类似但不同的问题,至少确认在正确的情况下,SQL服务器可能会给你不好的答案,并this related bug report使用这个关键短语:
描述:每个会话两个 很多人打电话给P程序 改变参数值。该 过程P执行一个查询 静态数据,有时使用OPTION (RECOMPILE),有时没有。
偶尔P会给出不正确的结果 (对于下面的repro,这通常是 发生率约为1/2% - 1%的时间)。 当P的结果错误时,P返回 预期数量的0或两倍 行。
有人昨天留下了关于参数嗅探的评论作为一种可能性,但无论出于何种原因,他们删除了他们的评论(或答案),所以我不能赞美他们的提示。
答案 1 :(得分:1)