SQL Server:快速查询,但过程缓慢


257

查询运行速度很快:

DECLARE @SessionGUID uniqueidentifier
SET @SessionGUID = 'BCBA333C-B6A1-4155-9833-C495F22EA908'

SELECT *
FROM Report_Opener
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank

子树成本:0.502

但是将相同的SQL放入存储过程运行速度很慢,并且执行计划完全不同

CREATE PROCEDURE dbo.ViewOpener @SessionGUID uniqueidentifier AS
SELECT *
FROM Report_Opener
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank

EXECUTE ViewOpener @SessionGUID

子树成本:19.2

我跑了

sp_recompile ViewOpener

而且它仍然运行相同(严重),并且我还将存储过程更改为

CREATE PROCEDURE dbo.ViewOpener @SessionGUID uniqueidentifier AS
SELECT *, 'recompile please'
FROM Report_Opener
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank

然后再次尝试真正诱使它重新编译。

我删除并重新创建了存储过程,以使其生成新计划。

我尝试通过使用诱饵变量来强制重新编译并防止参数嗅探

CREATE PROCEDURE dbo.ViewOpener @SessionGUID uniqueidentifier AS

DECLARE @SessionGUIDbitch uniqueidentifier
SET @SessionGUIDbitch = @SessionGUID

SELECT *
FROM Report_Opener
WHERE SessionGUID = @SessionGUIDbitch
ORDER BY CurrencyTypeOrder, Rank

我也尝试过定义存储过程WITH RECOMPILE

CREATE PROCEDURE dbo.ViewOpener @SessionGUID uniqueidentifier 
WITH RECOMPILE
AS
SELECT *
FROM Report_Opener
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank

因此它的计划永远不会被缓存,我尝试在执行时强制重新编译:

EXECUTE ViewOpener @SessionGUID WITH RECOMPILE

这没有帮助。

我尝试将过程转换为动态SQL:

CREATE PROCEDURE dbo.ViewOpener @SessionGUID uniqueidentifier 
WITH RECOMPILE AS
DECLARE @SQLString NVARCHAR(500)

SET @SQLString = N'SELECT *
   FROM Report_OpenerTest
   WHERE SessionGUID = @SessionGUID
   ORDER BY CurrencyTypeOrder, Rank'

EXECUTE sp_executesql @SQLString,
N'@SessionGUID uniqueidentifier',
@SessionGUID

这没有帮助。

实体“ Report_Opener”是未索引的视图。该视图仅引用基础表。没有表包含计算列,索引索引或其他索引。

对于它的地狱,我尝试使用创建视图

SET ANSI_NULLS ON
SET QUOTED_IDENTIFER ON

那没有解决。

怎么样

  • 查询很快
  • 将查询移至视图,然后从视图中进行选择非常快捷
  • 从存储过程的视图中选择速度慢40倍?

我尝试将视图的定义直接移到存储过程中(违反了3条业务规则,并破坏了重要的封装),这使其速度仅慢了约6倍。

为什么存储过程版本这么慢?有什么可能比运行另一种即席SQL更快地解释运行即席SQL的SQL Server?

我真的不愿意

  • 将SQL嵌入代码中
  • 完全更改代码

    Microsoft SQL Server  2000 - 8.00.2050 (Intel X86)
    Mar  7 2008 21:29:56
    Copyright (c) 1988-2003 Microsoft Corporation
    Standard Edition on Windows NT 5.2 (Build 3790: Service Pack 2)
    

但是,如果没有参数嗅探,导致SQL Server无法像运行查询的SQL Server一样快地运行的原因。


我的下一次尝试将有StoredProcedureA来电StoredProcedureB呼叫StoredProcedureC电话StoredProcedureD查询视图。

否则,让存储过程调用存储过程,调用UDF,调用UDF,调用存储过程,调用UDF来查询视图。


综上所述,以下内容从质量检查开始运行很快,但是在存储过程中运行起来却很慢:

原本的:

--Runs fine outside of a stored procedure
SELECT *
FROM Report_OpenerTest
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank

sp_executesql

--Runs fine outside of a stored procedure
DECLARE @SQLString NVARCHAR(500)
SET @SQLString = N'SELECT *
FROM Report_OpenerTest
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank'

EXECUTE sp_executesql @SQLString,
        N'@SessionGUID uniqueidentifier',
        @SessionGUID

EXEC(@sql)

--Runs fine outside of a stored procedure
DECLARE @sql NVARCHAR(500)
SET @sql = N'SELECT *
FROM Report_OpenerTest
WHERE SessionGUID = '''+CAST(@SessionGUID AS varchar(50))+'''
ORDER BY CurrencyTypeOrder, Rank'

EXEC(@sql)

执行计划

良好的计划:

      |--Sort(ORDER BY:([Expr1020] ASC, [Currencies].[Rank] ASC))
           |--Compute Scalar(DEFINE:([Expr1020]=If ([Currencies].[CurrencyType]='ctCanadianCash') then 1 else If ([Currencies].[CurrencyType]='ctMiscellaneous') then 2 else If ([Currencies].[CurrencyType]='ctTokens') then 3 else If ([Currencies].[CurrencyType]
                |--Nested Loops(Left Outer Join, OUTER REFERENCES:([Openers].[OpenerGUID]))
                     |--Filter(WHERE:((([Currencies].[IsActive]<>0 AND [Currencies].[OnOpener]<>0) AND ((((((([Currencies].[CurrencyType]='ctUSCoin' OR [Currencies].[CurrencyType]='ctMiscellaneousUS') OR [Currencies].[CurrencyType]='ctUSCash') OR [Currencies].
                     |    |--Nested Loops(Left Outer Join, OUTER REFERENCES:([Currencies].[CurrencyGUID], [Openers].[OpenerGUID]) WITH PREFETCH)
                     |         |--Nested Loops(Left Outer Join)
                     |         |    |--Bookmark Lookup(BOOKMARK:([Bmk1016]), OBJECT:([GrobManagementSystemLive].[dbo].[Windows]))
                     |         |    |    |--Nested Loops(Inner Join, OUTER REFERENCES:([Openers].[WindowGUID]))
                     |         |    |         |--Bookmark Lookup(BOOKMARK:([Bmk1014]), OBJECT:([GrobManagementSystemLive].[dbo].[Openers]))
                     |         |    |         |    |--Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[Openers].[IX_Openers_SessionGUID]), SEEK:([Openers].[SessionGUID]=[@SessionGUID]) ORDERED FORWARD)
                     |         |    |         |--Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[Windows].[IX_Windows]), SEEK:([Windows].[WindowGUID]=[Openers].[WindowGUID]) ORDERED FORWARD)
                     |         |    |--Clustered Index Scan(OBJECT:([GrobManagementSystemLive].[dbo].[Currencies].[IX_Currencies_CurrencyType]))
                     |         |--Clustered Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[OpenerDetails].[IX_OpenerDetails_OpenerGUIDCurrencyGUID]), SEEK:([OpenerDetails].[OpenerGUID]=[Openers].[OpenerGUID] AND [OpenerDetails].[CurrencyGUID]=[Currenc
                     |--Hash Match(Cache, HASH:([Openers].[OpenerGUID]), RESIDUAL:([Openers].[OpenerGUID]=[Openers].[OpenerGUID]))
                          |--Stream Aggregate(DEFINE:([Expr1006]=SUM(If (((([Currencies].[CurrencyType]='ctMiscellaneous' OR [Currencies].[CurrencyType]='ctTokens') OR [Currencies].[CurrencyType]='ctChips') OR [Currencies].[CurrencyType]='ctCanadianCoin') OR [
                               |--Nested Loops(Inner Join, OUTER REFERENCES:([OpenerDetails].[CurrencyGUID]) WITH PREFETCH)
                                    |--Nested Loops(Inner Join)
                                    |    |--Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[Openers].[IX_Openers_OneOpenerPerSession]), SEEK:([Openers].[OpenerGUID]=[Openers].[OpenerGUID]) ORDERED FORWARD)
                                    |    |--Clustered Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[OpenerDetails].[IX_OpenerDetails_OpenerGUIDCurrencyGUID]), SEEK:([OpenerDetails].[OpenerGUID]=[Openers].[OpenerGUID]) ORDERED FORWARD)
                                    |--Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[Currencies].[PK_Currencies_CurrencyGUID]), SEEK:([Currencies].[CurrencyGUID]=[OpenerDetails].[CurrencyGUID]) ORDERED FORWARD)

糟糕的计划

       |--Sort(ORDER BY:([Expr1020] ASC, [Currencies].[Rank] ASC))
            |--Compute Scalar(DEFINE:([Expr1020]=If ([Currencies].[CurrencyType]='ctCanadianCash') then 1 else If ([Currencies].[CurrencyType]='ctMiscellaneous') then 2 else If ([Currencies].[CurrencyType]='ctTokens') then 3 else If ([Currencies].[Currency
                 |--Nested Loops(Left Outer Join, OUTER REFERENCES:([Openers].[OpenerGUID]))
                      |--Filter(WHERE:((([Currencies].[IsActive]<>0 AND [Currencies].[OnOpener]<>0) AND ((((((([Currencies].[CurrencyType]='ctUSCoin' OR [Currencies].[CurrencyType]='ctMiscellaneousUS') OR [Currencies].[CurrencyType]='ctUSCash') OR [Currenc
                      |    |--Nested Loops(Left Outer Join, OUTER REFERENCES:([Currencies].[CurrencyGUID], [Openers].[OpenerGUID]) WITH PREFETCH)
                      |         |--Filter(WHERE:([Openers].[SessionGUID]=[@SessionGUID]))
                      |         |    |--Concatenation
                      |         |         |--Nested Loops(Left Outer Join)
                      |         |         |    |--Table Spool
                      |         |         |    |    |--Hash Match(Inner Join, HASH:([Windows].[WindowGUID])=([Openers].[WindowGUID]), RESIDUAL:([Windows].[WindowGUID]=[Openers].[WindowGUID]))
                      |         |         |    |         |--Clustered Index Scan(OBJECT:([GrobManagementSystemLive].[dbo].[Windows].[IX_Windows_CageGUID]))
                      |         |         |    |         |--Table Scan(OBJECT:([GrobManagementSystemLive].[dbo].[Openers]))
                      |         |         |    |--Table Spool
                      |         |         |         |--Clustered Index Scan(OBJECT:([GrobManagementSystemLive].[dbo].[Currencies].[IX_Currencies_CurrencyType]))
                      |         |         |--Compute Scalar(DEFINE:([Openers].[OpenerGUID]=NULL, [Openers].[SessionGUID]=NULL, [Windows].[UseChipDenominations]=NULL))
                      |         |              |--Nested Loops(Left Anti Semi Join)
                      |         |                   |--Clustered Index Scan(OBJECT:([GrobManagementSystemLive].[dbo].[Currencies].[IX_Currencies_CurrencyType]))
                      |         |                   |--Row Count Spool
                      |         |                        |--Table Spool
                      |         |--Clustered Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[OpenerDetails].[IX_OpenerDetails_OpenerGUIDCurrencyGUID]), SEEK:([OpenerDetails].[OpenerGUID]=[Openers].[OpenerGUID] AND [OpenerDetails].[CurrencyGUID]=[Cu
                      |--Hash Match(Cache, HASH:([Openers].[OpenerGUID]), RESIDUAL:([Openers].[OpenerGUID]=[Openers].[OpenerGUID]))
                           |--Stream Aggregate(DEFINE:([Expr1006]=SUM([partialagg1034]), [Expr1007]=SUM([partialagg1035]), [Expr1008]=SUM([partialagg1036]), [Expr1009]=SUM([partialagg1037]), [Expr1010]=SUM([partialagg1038]), [Expr1011]=SUM([partialagg1039]
                                |--Nested Loops(Inner Join)
                                     |--Stream Aggregate(DEFINE:([partialagg1034]=SUM(If (((([Currencies].[CurrencyType]='ctMiscellaneous' OR [Currencies].[CurrencyType]='ctTokens') OR [Currencies].[CurrencyType]='ctChips') OR [Currencies].[CurrencyType]='
                                     |    |--Nested Loops(Inner Join, OUTER REFERENCES:([OpenerDetails].[CurrencyGUID]) WITH PREFETCH)
                                     |         |--Clustered Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[OpenerDetails].[IX_OpenerDetails_OpenerGUIDCurrencyGUID]), SEEK:([OpenerDetails].[OpenerGUID]=[Openers].[OpenerGUID]) ORDERED FORWARD)
                                     |         |--Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[Currencies].[PK_Currencies_CurrencyGUID]), SEEK:([Currencies].[CurrencyGUID]=[OpenerDetails].[CurrencyGUID]) ORDERED FORWARD)
                                     |--Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[Openers].[IX_Openers_OneOpenerPerSession]), SEEK:([Openers].[OpenerGUID]=[Openers].[OpenerGUID]) ORDERED FORWARD)

坏人急于缓存600万行。另一个不是。

注意:这不是有关优化查询的问题。我有一个查询,运行速度很快。我只希望SQL Server从存储过程中快速运行。


我注意到每次您将一个参数重新分配给另一个参数,然后在以后的查询中使用它时,都可能会发生这种情况,并且正如答案所示,针对未知的@“ someparamname”进行优化可以起作用。
JustDave

Answers:


404

我和原始海报有相同的问题,但引用的答案并不能解决我的问题。从存储过程来看,查询仍然运行缓慢。

感谢Omnibuzz,我在这里找到了另一个答案“ Parameter Sniffing”。归结为在存储过程查询中使用“局部变量”,但是请阅读原始内容以获取更多理解,这是一篇很棒的文章。例如

慢速方式:

CREATE PROCEDURE GetOrderForCustomers(@CustID varchar(20))
AS
BEGIN
    SELECT * 
    FROM orders
    WHERE customerid = @CustID
END

快速方式:

CREATE PROCEDURE GetOrderForCustomersWithoutPS(@CustID varchar(20))
AS
BEGIN
    DECLARE @LocCustID varchar(20)
    SET @LocCustID = @CustID

    SELECT * 
    FROM orders
    WHERE customerid = @LocCustID
END

希望这对其他人有帮助,这样做可以将我的执行时间从5分钟以上减少到6-7秒左右。


23
+1但是,这很奇怪,并且提出了很多问题,例如我们应该对所有程序执行此操作吗?如果不执行此操作,何时执行此操作?
gotqn 2014年

31
我是唯一对此行为感到困惑的人吗?是否需要声明局部变量以防止参数嗅探?SQL Server是否不应该足够聪明才能阻止这种情况发生呢?微软的短视设计恕我直言,这只会导致不必要的代码膨胀。
l46kok 2015年

4
15分钟-> 8秒!救生员
Tony Brix

3
@BennettDill WITH RECOMPILE对我没有影响,仅对本地参数有效。
mrogers

8
现在可以使用查询提示来实现这一点-OPTION(OPTIMIZE FOR(@varA UNKNOWN,@ varB UNKNOWN))
Dave

131

我发现了问题,这是存储过程的慢速和快速版本的脚本:

dbo.ViewOpener__RenamedForCruachan__Slow.PRC

SET QUOTED_IDENTIFIER OFF 
GO
SET ANSI_NULLS OFF 
GO

CREATE PROCEDURE dbo.ViewOpener_RenamedForCruachan_Slow
    @SessionGUID uniqueidentifier
AS

SELECT *
FROM Report_Opener_RenamedForCruachan
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank
GO

SET QUOTED_IDENTIFIER OFF 
GO
SET ANSI_NULLS ON 
GO

dbo.ViewOpener__RenamedForCruachan__Fast.PRC

SET QUOTED_IDENTIFIER OFF 
GO
SET ANSI_NULLS ON 
GO

CREATE PROCEDURE dbo.ViewOpener_RenamedForCruachan_Fast
    @SessionGUID uniqueidentifier 
AS

SELECT *
FROM Report_Opener_RenamedForCruachan
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank
GO

SET QUOTED_IDENTIFIER OFF 
GO
SET ANSI_NULLS ON 
GO

如果您没有发现差异,我不会怪您。区别根本不在存储过程中。区别在于将快速的0.5成本查询转换为一个可以快速执行600万行的后台处理的查询:

慢: SET ANSI_NULLS OFF

快速: SET ANSI_NULLS ON


由于该视图确实具有一个join子句,该回答也可以使之有意义:

(table.column IS NOT NULL)

因此NULL涉及到一些。


返回Query Analizer并运行,可以进一步证明该解释。

SET ANSI_NULLS OFF

DECLARE @SessionGUID uniqueidentifier
SET @SessionGUID = 'BCBA333C-B6A1-4155-9833-C495F22EA908'

SELECT *
FROM Report_Opener_RenamedForCruachan
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank

而且查询很慢。


因此问题不是因为查询是从存储过程中运行的。问题在于企业管理器的连接默认选项是ANSI_NULLS off,而不是ANSI_NULLS onQA的默认选项。

Microsoft在KB296769中确认了这一事实(BUG:无法使用SQL Enterprise Manager创建包含链接服务器对象的存储过程)。解决方法是ANSI_NULLS在存储过程对话框中包括该选项:

Set ANSI_NULLS ON
Go
Create Proc spXXXX as
....

2
我仍然不明白转弯如何ANSI_NULLS ON使如此巨大的性能差异。
贾斯汀·赫尔格森

2
@ Ek0nomik因为JOIN视图中的子句在时具有不同的含义ANSI_NULLS OFF。行突然匹配,导致优化器完全不同地运行查询。想象一下,它们没有消除所有行的99.9%,而是突然返回。
伊恩·博伊德

2
注意: ANSI_NULLS OFF不建议使用,并认为这是一种不好的做法
让·吉恩

2
链接 “在SQL Server的未来版本中,ANSI_NULLS将始终为ON,并且任何将选项显式设置为OFF的应用程序都将产生错误。请避免在新的开发工作中使用此功能,并计划修改当前使用此功能的应用程序。 ”
sotn

对我的情况没有帮助。
st_stefanov

19

对您的数据库执行此操作。我有一个同样的问题-它在一个数据库中工作正常,但是当我使用SSIS导入将该数据库复制到另一个数据库时(不是通常的还原),大多数存储过程都会发生此问题。因此,在进一步搜索之后,我发现了Pinal Dave博客(顺便说一句,我遇到了他的大部分帖子,并且确实对我有很大帮助,非常感谢Pinal Dave)

我在数据库上执行以下查询,它纠正了我的问题:

EXEC sp_MSforeachtable @command1="print '?' DBCC DBREINDEX ('?', ' ', 80)"
GO
EXEC sp_updatestats
GO 

希望这可以帮助。只是传递了其他帮助我的帮助。


2
仅供以后阅读的读者参考:DBCC REINDEX已弃用,因此您应该寻找替代方法。
gvee

1
解决了我的问题,谢谢(1分20秒降为2秒!)。回复:DBCC DBREINDEXMS说:“此功能将在将来的Microsoft SQL Server版本中删除。请勿在新开发工作中使用此功能,而应尽快修改当前使用此功能的应用程序。而应使用ALTER INDEX。”
AjV Jsy

不知道这是否是最好的答案,但就我而言,sp_updatestats已全部解决,因此+1
Todd Menier

..是的,并且不要忘记重建索引可能会花费时间和空间,因此在生产服务器上执行重建索引之前,请确保可以承受可能的速度下降。我建议您考虑进行重组或重建(在线=开)
米兰

14

我遇到了同样的问题,这篇文章对我很有帮助,但是没有任何发布的答案可以解决我的特定问题。我想发布对我有用的解决方案,希望它可以对其他人有所帮助。

https://stackoverflow.com/a/24016676/814299

在查询末尾,添加OPTION(OPTIMIZE FOR(@now UNKNOWN))


4

这次您发现了问题。如果下次您不太幸运,无法解决问题,则可以冻结计划,而不必担心执行计划错误。


根据该博客条目,计划冻结仅适用于MS SQL 2005及更高版本,因此对OP毫无帮助。
Coxy

问题是它使用了错误的查询计划。我不想将其冻结到错误的位置。
伊恩·博伊德

4

我遇到了这个问题。我的查询看起来像:

select a, b, c from sometable where date > '20140101'

我的存储过程定义如下:

create procedure my_procedure (@dtFrom date)
as
select a, b, c from sometable where date > @dtFrom

我将数据类型更改为datetime和voila!从30分钟到1分钟!

create procedure my_procedure (@dtFrom datetime)
as
select a, b, c from sometable where date > @dtFrom

2
谢谢李,这挽救了我的一天!这是我如何只获取日期时间字段的日期部分的方法:DATEADD(dd,0,DATEDIFF(dd,0,table.field))
Julien B.

1
这解决了我的问题。一旦将参数类型设置为与列类型相同,就可以使用varchar(20)列,而我的参数是nvarchar(50)-不再有延迟。
st_stefanov

3

您是否尝试过重建Report_Opener表上的统计信息和/或索引。如果统计信息仍然显示数据库首次启动时的数据,则SP的所有重新兼容都将一文不值。

初始查询本身可以快速工作,因为优化器可以看到该参数永远不会为null。对于SP,优化器无法确保该参数永远不会为null。


有没有一种方法可以在存储过程声明中指示i参数不能为null?而且sp_executesql是否可以解决此问题?
伊恩·博伊德

言归正传,不是在2000年。2005年添加了查询提示,您可以在其中提供参数的示例值,优化器将进行优化,就好像它知道始终使用该参数一样。话虽这么说,但我通常认为这种事情是统计问题。
AnthonyWJones

如果是统计问题,当我临时运行sp_executesql,exec()时,他们可以通过质量检查正常运行。当存储过程包含临时sql,sp_executesql,exec()时,为什么它们都然后运行不佳?
伊恩·博伊德

1

尽管我通常对此表示反对(尽管在这种情况下,您似乎有道理),但您是否尝试过在查询的SP版本上提供任何查询提示?如果SQL Server在这两个实例中准备了一个不同的执行计划,则可以使用提示来告诉它使用哪个索引,以便该计划与第一个索引匹配吗?

对于某些示例,您可以转到此处

编辑:如果您可以在此处发布查询计划,也许我们可以确定计划之间的区别。

第二:将链接更新为特定于SQL-2000。您必须向下滚动一种方式,但是第二个标题为“表格提示”就是您要的内容。

第三:“ Bad”查询似乎忽略了“ Openers”表上的[IX_Openers_SessionGUID]-添加INDEX提示以强制其使用该索引是否有可能改变事情?


该参考中最有用的查询提示在此处讨论的SQL 2000上不可用。
AnthonyWJones

另外,需要什么提示?当我临时运行SQL Server时,它可以解决所有问题。
伊恩·博伊德

当然,这也是我的经验。但是,在这种情况下,他是说要提出一个完全不同的执行计划。也许有一个临时使用的索引,但是由于某些原因在proc中被忽略了。他可以强制SQL Server使用带有“ INDEX”提示的索引。
SqlRyan

1

这可能不太可能,但是鉴于您观察到的行为异常,需要对其进行检查,并且没有其他人提到它。

您是否绝对确定所有对象都归dbo所有,并且您没有自己或其他用户拥有的流氓副本?

偶尔,当我看到奇怪的行为时,这是因为实际上有一个对象的两个副本,而要获得的则取决于指定的对象和登录的对象。例如,完全有可能具有相同名称但由不同所有者拥有的视图或过程的两个副本-这种情况可能会出现,您没有以dbo身份登录数据库而忘记了在指定时将dbo指定为对象所有者您创建对象。

请注意,在文本中,您正在运行某些事情而未指定所有者,例如

sp_recompile ViewOpener

例如,如果存在dbo和[某些其他用户]拥有的viewOpener的两个副本,那么如果您未指定,则实际重新编译的哪个取决于环境。与Report_Opener视图同上-如果在哪里有两个副本(它们的规格或执行计划可能不同),则所使用的副本取决于情况-并且由于您未指定所有者,因此您的即席查询很有可能使用一个副本,而编译过的程序可能会使用其他。

正如我所说,这不太可能,但是有可能并且应该进行检查,因为您的问题可能是您只是在错误的位置寻找错误。


1

这听起来可能很愚蠢,从名称SessionGUID看来似乎很明显,但是该列是Report_Opener上的uniqueidentifier吗?如果不是,则可能要尝试将其强制转换为正确的类型并尝试一下,或将变量声明为正确的类型。

作为存储过程一部分创建的计划可能会不直观地工作,并且会在大型表上进行内部转换。


它不是。但是我看到了where子句将一个varchar列与一个nvarchar值(Eg WHERE CustomerName = N'zrendall')相比较的性能问题。nvarchar在比较之前,SQL Server必须向上将每个列的值转换为一个。
伊恩·博伊德

0

我还有一个主意。如果创建此基于表的函数怎么办:

CREATE FUNCTION tbfSelectFromView
(   
    -- Add the parameters for the function here
    @SessionGUID UNIQUEIDENTIFIER
)
RETURNS TABLE 
AS
RETURN 
(
    SELECT *
    FROM Report_Opener
    WHERE SessionGUID = @SessionGUID
    ORDER BY CurrencyTypeOrder, Rank
)
GO

然后使用以下语句从中选择(甚至将其放入您的SP中):

SELECT *
FROM tbfSelectFromView(@SessionGUID)

似乎正在发生的事情(每个人都已经在评论)SQL Server只是在错误的地方做出了一个假设,也许这将迫使它纠正这个假设。我讨厌添加额外的步骤,但是我不确定还会导致什么。


0

-这是解决方案:

create procedure GetOrderForCustomers(@CustID varchar(20))

as

begin

select * from orders

where customerid = ISNULL(@CustID, '')

end

- 而已

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.