2

我有一个存储过程,用于处理大约 90,000 条记录以返回各种信息;我只是加入一个 SQL 表来过滤要运行的记录(在我的 vb.net 批处理使用它之前从另一个进程加载)。现在,我需要拥有与存储过程中完全相同的逻辑,可用于通过 Windows 应用程序为个人运行的 90,000 人。我最初的想法是使用相同的存储过程(不重复逻辑)并且只有一个加载/使用的临时表变量:--传入的memberID(在通过windows应用程序的情况下)或--包含 90,000 个成员的表(如果没有传入 memberID 并从批处理中调用)。我担心的是,如果它有时用于单个行,有时用于 90,000 行,它可能会对查询计划产生什么影响。性能和效率将如何受到影响?这是一个好主意吗?还是应该只是具有重复逻辑的单独存储过程?

**以下是关于我正在谈论的内容的更多详细信息。我试图简化它,并且还必须重命名所有内容才能在线显示。

--===========================================================================================
--The first query is getting all the members information for the batch run.
--It is joining to a tmpMembers table which is loaded with the members for the batch run 
--(filtering it down to approxiately 90,000 members for that batch run)

CREATE PROCEDURE s_GetMembersInfoSEL
AS
SELECT * --Includes a great deal of output (some of which is calculated before being returned)
FROM Members m 
INNER JOIN tmpMembers tm
  ON tm.MbrID = m.MbrID
--Also a bunch of other joins to member, claim, service, etc tables for the additional info.  

--===========================================================================================

--Proposed changes...

CREATE PROCEDURE s_GetMembersInfoSEL
                            @MbrID INT = NULL
AS
DECLARE @MbrsTable TABLE (MbrID INT  PRIMARY KEY)

IF @MbrID IS NULL
  BEGIN 
    INSERT INTO @MbrsTable          
    SELECT MbrID
    FROM tmpMembers
  END
ELSE
  BEGIN 
    INSERT INTO @MbrsTable
                (MbrID)         
    VALUES (@MbrID)
  END  

SELECT * --Includes a great deal of output (some of which is calculated before being returned)
FROM Members m 
INNER JOIN @MbrsTable tm
  ON tm.MbrID = m.MbrID
--Also a bunch of other joins to member, claim, service, etc tables for the additional info.  
4

1 回答 1

1

您使用表变量的方式可能会导致使用效率低下的计划。

从文章查询性能和表变量

编译包含表变量的批处理或存储过程时,表变量的行数是未知的。因此,优化器必须做出一些假设。 它估计表变量的行数非常少。这会导致计划效率低下。 大多数时候,嵌套循环连接与表变量一起用作外部表。如果表变量中存在大量行,这将导致内表被执行多次。

...

如果您有大量行要填充到表变量中,请考虑使用此解决方案。 您可以将选项重新编译添加到涉及表变量与其他表连接的语句中。通过这样做,SQL Server 将能够在重新编译时检测行数,因为这些行已经被填充。 此选项仅适用于 SQL Server 2005 及更高版本。

(重点补充)

您更新后的查询如下所示:

SELECT *
FROM Members m 
INNER JOIN @MbrsTable tm
  ON tm.MbrID = m.MbrID
OPTION (RECOMPILE)

但是,请注意,如果存储过程执行得足够频繁,重新编译可能会导致其自身的性能问题。在这种情况下,您可能会考虑使用不同的方式来整合此逻辑,例如使用视图或用户定义的函数,并将这两种不同的场景拆分为单独的查询并避免使用表变量。

于 2012-12-10T17:01:30.070 回答