【问题标题】:SQL why sp is slower than querySQL为什么sp比查询慢
【发布时间】:2015-04-07 09:34:20
【问题描述】:

这可能看起来很简单的问题,但我真的需要帮助。我已经尝试了两天了。

我将 userid 作为参数传递给存储过程,并使用该 userid 检索 companyid 以在另一个查询中使用它。 p>

CREATE PROC spXXXXXXX
@UserID INT
AS
BEGIN
DECLARE @CompanyID INT
SET @CompanyID =(SELECT CompanyID FROM User WHERE UserID=@UserID)

SELECT
            DISTINCT (U.UserID),
            U.UserName, 
            U.FirstName,
            U.LastName,
            C.CompanyName,
            U.Email,
            U.IsActive,
    FROM    
            [User] U
    LEFT OUTER JOIN 
            Company C
        ON
            C.CompanyID =U.CompanyID 
    WHERE   
            U.CompanyID=@CompanyID 
END  

执行需要超过 30 秒。但如果我将值直接传递给查询,则只需 1 秒。 SET 需要更多时间来执行。

所以我尝试使用 CTE 来加快查询速度,但没有运气。仅限同一时间。

;WITh cte(CompanyID)
        as
        (
        SELECT CompanyID FROM [User] WHERE UserID=@CurrentUserId
        ) 

   SELECT
            DISTINCT (U.UserID),
            U.UserName, 
            U.FirstName,
            U.LastName,
            C.CompanyName,
            U.Email,
            U.IsActive,
    FROM    
            [User] U
    LEFT OUTER JOIN 
            Company C
        ON
            C.CompanyID =U.CompanyID 
    LEFT OUTER JOIN 
            cte CS
        ON  
            CS.CompanyID =C.CompanyID
    WHERE   
            U.CompanyID=CS.CompanyID 

返回 31 条记录仍然需要 27 秒。如果我直接传递值意味着只需要一秒钟..我做错了什么?

【问题讨论】:

  • 执行计划显示什么?
  • 我猜引擎一开始就使用了错误的计划。您是否尝试使用 ALTER PROC spXXXXXXX WITH RECOMPILE 选项更改存储过程。 ?
  • 可能是parameter sniffing,但基本上不可能说没有看到执行计划。最简单的检查方法是标记重新编译的过程(EXECUTE sp_recompile N'spXXXXXXX'),而不是强制它重新编译每次执行(如WITH RECOMPILE 那样)
  • 这个查询不一样,你的@companyID在第二个例子中来自哪里?
  • 您应该将执行计划作为图像添加到您的问题中。添加您在表上拥有的任何索引的详细信息也可能很有用。每张表有多少条记录?

标签: sql sql-server sql-server-2008 sql-server-2008-r2


【解决方案1】:

您可能会因使用中间变量而遭受隐式 OPTION(OPTIMIZE FOR UNKNOWN) 的困扰。见here。优化器无法以这种方式为您的查询提供良好的计划。

如果@CurrentUserID 是变量而不是参数,则第二个查询也会遇到同样的问题。试试这个查询,看看它是否会执行得更好:

CREATE PROC spXXXXXXX
    @UserID INT
AS
SELECT DISTINCT 
    U.UserID,
    U.UserName, 
    U.FirstName,
    U.LastName,
    C.CompanyName,
    U.Email,
    U.IsActive,
FROM [User] CU -- current user
INNER JOIN [User] U -- users with same company
ON      CU.CompanyID = U.CompanyID
LEFT JOIN Company C
ON      C.CompanyID =U.CompanyID 
WHERE   CU.[UserID] = @UserID

参数嗅探可能仍然存在一些问题,但这应该有助于优化器为您的过程生成更好的执行计划。

【讨论】:

    【解决方案2】:

    尝试以下方法,看看是否有帮助... 为用户创建一个局部变量,以避免参数嗅探。

    declare @local_UserId int 
      select @local_UserId = @UserID
    
      DECLARE @CompanyID INT
        SET @CompanyID =(SELECT CompanyID FROM User WHERE UserID=@local_UserId)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-12
      • 2010-10-05
      • 2021-03-22
      • 1970-01-01
      • 1970-01-01
      • 2016-06-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多