提高sql查询的性能

提高sql查询的性能,sql,sql-server-2008-r2,query-performance,Sql,Sql Server 2008 R2,Query Performance,我正在寻找一些技巧/窍门,以提高在表中插入多个SELECT语句的存储过程的性能。我加入的所有对象都已编制索引 我相信这个存储过程运行几乎需要一个小时的原因是,有多个SELECT语句使用以下两个视图:rvw_FinancialInItemValues和rvw_FinancialInItems 此外,每个SELECT语句都使用特定的硬编码值作为AccountNumber、LineItemTypeID和来自上述两个视图的少数其他字段值 如果我创建一个临时表,一次获取这些SELECT语句所需的所有数据,

我正在寻找一些技巧/窍门,以提高在表中插入多个SELECT语句的存储过程的性能。我加入的所有对象都已编制索引

我相信这个存储过程运行几乎需要一个小时的原因是,有多个SELECT语句使用以下两个视图:rvw_FinancialInItemValues和rvw_FinancialInItems

此外,每个SELECT语句都使用特定的硬编码值作为AccountNumber、LineItemTypeID和来自上述两个视图的少数其他字段值

如果我创建一个临时表,一次获取这些SELECT语句所需的所有数据,然后在联接中使用这个临时表,会提高性能吗

有没有其他方法可以提高性能和可管理性

        SELECT
         @scenarioid,
         @portfolioid,
         pa.Id,
         pa.ExternalID,       
         (select value from fn_split(i.AccountNumber,'.') where id = 1),
         ac.[Description],
         cl.Name,
         NullIf((select value from fn_split(i.AccountNumber,'.') where id = 2),''),
         NullIf((select value from fn_split(i.AccountNumber,'.') where id = 3),''),
         ty.Name,
         v.[Date],
         cast(SUM(v.Amount) as decimal(13,2)),
         GETDATE()

    FROM rvw_FinancialLineItems i
    INNER JOIN rvw_Scenarios sc
        ON i.ScenarioId = sc.Id
        AND sc.Id = @scenarioid
        AND sc.PortfolioId = @portfolioid
    INNER JOIN #pa AS pa
        ON i.PropertyAssetID = pa.Id
    INNER JOIN rvw_FinancialLineItemValues v
        ON i.ScenarioId = v.ScenarioId
        AND i.PropertyAssetID = v.PropertyAssetID
        AND i.Id = v.FinancialLineItemId
        AND ((i.BusinessEntityTypeId = 11
        AND i.LineItemTypeId = 3002)
        OR (i.LineItemTypeId IN (2005, 2010, 2003, 2125, 2209, 5012, 6001)
        AND i.ModeledEntityKey = 1))
        AND i.AccountNumber not in ('401ZZ','403ZZ')
  AND i.AccountNumber not in ('401XX')
        AND i.AccountNumber not in ('40310','41110','42010','41510','40190','40110')  -- exclude lease-level revenues selected below
        AND v.[Date] BETWEEN @fromdate AND 
          CASE
            WHEN pa.AnalysisEnd < @todate THEN pa.AnalysisEnd
            ELSE @todate
          END
        AND v.ResultSet IN (0, 4)
    INNER JOIN rvw_Portfolios po
        ON po.Id = @portfolioid
    INNER JOIN Accounts ac
        ON po.ChartOfAccountId = ac.ChartOfAccountId
        AND i.AccountNumber = ac.AccountNumber
        AND ac.HasSubAccounts = 0
    INNER JOIN fn_LookupClassTypes() cl
        ON ac.ClassTypeId = cl.Id
    INNER JOIN LineItemTypes ty
        ON ac.LineItemTypeId = ty.Id
    LEFT JOIN OtherRevenues r
        ON i.PropertyAssetID = r.PropertyAssetID
        AND i.AccountNumber = r.AccountID
        AND v.[Date] BETWEEN r.[Begin] AND r.[End]
    WHERE (r.IsMemo IS NULL
    OR r.IsMemo = 0)
    GROUP BY    pa.AnalysisBegin
                ,pa.Id
                ,pa.ExternalID
                ,i.AccountNumber
                ,ac.[Description]
                ,cl.Name
                ,ty.Name
                ,v.[Date]
    HAVING SUM(v.amount) <> 0

您应该使用SET SHOWPLAN ALL ON或Management Studio Save Execution Plan运行查询,并查找效率低下的情况

有一些在线资源可帮助分析结果,例如:


另请参见

您应该使用SET SHOWPLAN ALL ON或Management Studio Save Execution Plan运行查询,并查找效率低下的情况

有一些在线资源可帮助分析结果,例如:


另请参见

我将首先看以下内容。这里与存储过程相关的等待类型是什么?您是否看到大量的磁盘io时间?事情是在记忆中进行的吗?可能是网络延迟导致了这么多信息

接下来,程序的计划是什么样子的,它在哪里显示所有正在完成的工作


正如你提到的,这些观点肯定会成为一个问题。您可以使用预处理的表,这样就不必进行那么多的联接。特别是那些CPU使用量最大的连接

我首先要看以下几点。这里与存储过程相关的等待类型是什么?您是否看到大量的磁盘io时间?事情是在记忆中进行的吗?可能是网络延迟导致了这么多信息

接下来,程序的计划是什么样子的,它在哪里显示所有正在完成的工作


正如你提到的,这些观点肯定会成为一个问题。您可以使用预处理的表,这样就不必进行那么多的联接。特别是那些CPU使用量最大的连接

相关子查询通常速度较慢,在尝试提高性能时不应使用。使用fn_split创建临时表索引(如果需要),然后连接到它以获得所需的值。您可能需要多次加入不同的值,而实际上不知道我很难可视化的数据

它也不利于性能的使用或维护。在派生表中改用UNION ALL

由于视图rvw_FinancialInItems上有所有这些条件,因此可以将这些条件提取到临时表中,然后索引临时表


您还可能会看到使用视图是否是一个好主意。通常视图与许多您无法从中获取数据的表有连接,因此性能不如仅查询您实际需要的表。如果您的组织愚蠢到可以生成调用视图的视图,则尤其如此。

相关子查询通常速度较慢,在您尝试提高性能时,不应使用相关子查询。使用fn_split创建临时表索引(如果需要),然后连接到它以获得所需的值。您可能需要多次加入不同的值,而实际上不知道我很难可视化的数据

它也不利于性能的使用或维护。在派生表中改用UNION ALL

由于视图rvw_FinancialInItems上有所有这些条件,因此可以将这些条件提取到临时表中,然后索引临时表

您还可能会看到使用视图是否是一个好主意。通常视图与许多您无法从中获取数据的表有连接,因此性能不如仅查询您实际需要的表。如果您的组织愚蠢到可以创建称为视图的视图,则尤其如此。

首先,您使用的是哪个fn\u分割UDF?如果您不使用表值内联UDF,那么这是出了名的慢

其次,UDF fn_LookupClassTypes是一个内联表值的UDF吗?如果不是,则将其转换为内联表值UDF

最后,您的SQL查询有一些冗余。试试这个,看看它能做什么

SELECT @scenarioid, @portfolioid, pa.Id, pa.ExternalID,       
      (select value from fn_split(i.AccountNumber,'.') 
       where id = 1),  ac.[Description], cl.Name,
     NullIf((select value from fn_split(i.AccountNumber,'.') 
             where id = 2),''),
     NullIf((select value from fn_split(i.AccountNumber,'.') 
             where id = 3),''), ty.Name, v.[Date],
     cast(SUM(v.Amount) as decimal(13,2)), GETDATE()

FROM rvw_FinancialLineItems i
   JOIN rvw_Scenarios sc ON sc.Id = i.ScenarioId 
   JOIN #pa AS pa ON pa.Id = i.PropertyAssetID  
   JOIN rvw_FinancialLineItemValues v
      ON v.ScenarioId = i.ScenarioId
        AND v.PropertyAssetID = i.PropertyAssetID
        AND v.FinancialLineItemId = i.Id  
   JOIN rvw_Portfolios po ON po.Id = sc.portfolioid
   JOIN Accounts ac
      ON ac.ChartOfAccountId = po.ChartOfAccountId
         AND ac.AccountNumber = i.AccountNumber
   JOIN fn_LookupClassTypes() cl On cl.Id = ac.ClassTypeId 
   JOIN LineItemTypes ty On ty.Id = ac.LineItemTypeId
   Left JOIN OtherRevenues r
      ON r.PropertyAssetID = i.PropertyAssetID
        AND r.AccountID = i.AccountNumber  
        AND v.[Date] BETWEEN r.[Begin] AND r.[End]

WHERE i.ScenarioId = @scenarioid
   and ac.HasSubAccounts = 0
   and sc.PortfolioId = @portfolioid
   and IsNull(r.IsMemo, 0) = 0)
   and v.ResultSet In (0, 4)
   and i.AccountNumber not in
          ('401XX', '401ZZ','403ZZ','40310','41110',
           '42010','41510','40190','40110')
   and v.[Date] BETWEEN @fromdate AND 
            CASE WHEN pa.AnalysisEnd < @todate 
                 THEN pa.AnalysisEnd ELSE @todate END
   and ((i.LineItemTypeId = 3002 and i.BusinessEntityTypeId = 11) OR 
           (i.ModeledEntityKey = 1 and i.LineItemTypeId IN 
               (2005, 2010, 2003, 2125, 2209, 5012, 6001)))

GROUP BY pa.AnalysisBegin,pa.Id, pa.ExternalID, i.AccountNumber, 
      ac.[Description],cl.Name,ty.Name,v.[Date]
HAVING SUM(v.amount) <> 0
首先,您使用的是哪种fn_分割自定义项?如果您不使用表值内联UDF,那么这是出了名的慢

其次,UDF fn_LookupClassTypes是一个内联表值的UDF吗?如果不是,则将其转换为内联表值UDF

最后,您的SQL查询有一些冗余。试试这个,看看它能做什么

SELECT @scenarioid, @portfolioid, pa.Id, pa.ExternalID,       
      (select value from fn_split(i.AccountNumber,'.') 
       where id = 1),  ac.[Description], cl.Name,
     NullIf((select value from fn_split(i.AccountNumber,'.') 
             where id = 2),''),
     NullIf((select value from fn_split(i.AccountNumber,'.') 
             where id = 3),''), ty.Name, v.[Date],
     cast(SUM(v.Amount) as decimal(13,2)), GETDATE()

FROM rvw_FinancialLineItems i
   JOIN rvw_Scenarios sc ON sc.Id = i.ScenarioId 
   JOIN #pa AS pa ON pa.Id = i.PropertyAssetID  
   JOIN rvw_FinancialLineItemValues v
      ON v.ScenarioId = i.ScenarioId
        AND v.PropertyAssetID = i.PropertyAssetID
        AND v.FinancialLineItemId = i.Id  
   JOIN rvw_Portfolios po ON po.Id = sc.portfolioid
   JOIN Accounts ac
      ON ac.ChartOfAccountId = po.ChartOfAccountId
         AND ac.AccountNumber = i.AccountNumber
   JOIN fn_LookupClassTypes() cl On cl.Id = ac.ClassTypeId 
   JOIN LineItemTypes ty On ty.Id = ac.LineItemTypeId
   Left JOIN OtherRevenues r
      ON r.PropertyAssetID = i.PropertyAssetID
        AND r.AccountID = i.AccountNumber  
        AND v.[Date] BETWEEN r.[Begin] AND r.[End]

WHERE i.ScenarioId = @scenarioid
   and ac.HasSubAccounts = 0
   and sc.PortfolioId = @portfolioid
   and IsNull(r.IsMemo, 0) = 0)
   and v.ResultSet In (0, 4)
   and i.AccountNumber not in
          ('401XX', '401ZZ','403ZZ','40310','41110',
           '42010','41510','40190','40110')
   and v.[Date] BETWEEN @fromdate AND 
            CASE WHEN pa.AnalysisEnd < @todate 
                 THEN pa.AnalysisEnd ELSE @todate END
   and ((i.LineItemTypeId = 3002 and i.BusinessEntityTypeId = 11) OR 
           (i.ModeledEntityKey = 1 and i.LineItemTypeId IN 
               (2005, 2010, 2003, 2125, 2209, 5012, 6001)))

GROUP BY pa.AnalysisBegin,pa.Id, pa.ExternalID, i.AccountNumber, 
      ac.[Description],cl.Name,ty.Name,v.[Date]
HAVING SUM(v.amount) <> 0
你有什么看法吗
查看查询执行计划和/或估计以查看是否有特定节点导致大部分执行时间?是否查看查询执行计划和/或估计以查看是否有特定节点导致大部分执行时间?