【问题标题】:Improve performance of a sql query提高 sql 查询的性能
【发布时间】:2016-12-14 16:16:32
【问题描述】:

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

我相信这个存储过程需要将近一个小时才能运行的原因是因为有多个 SELECT 语句使用以下两个视图:rvw_FinancialLineItemValues 和 rvw_FinancialLineItems

此外,每个 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

【问题讨论】:

  • 您是否查看过查询执行计划和/或估计是否存在导致大部分执行时间的特定节点?

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


【解决方案1】:

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

网上有一些资源可以帮助分析结果,例如: http://www.sqlservercentral.com/articles/books/65831/

另见How do I obtain a Query Execution Plan?

【讨论】:

    【解决方案2】:

    首先,您使用的是哪个fn_split() UDF?如果您没有使用 table-Valued 内联 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
    

    【讨论】:

      【解决方案3】:

      我会先看看以下内容。与您的存储过程相关的等待类型是什么?您是否看到很多磁盘 io 时间?事情是在记忆中完成的吗?也许有网络延迟拉了这么多信息。

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

      正如您所提到的,这些观点肯定是一个问题。您可能有预处理表,因此您不必进行尽可能多的连接。特别是您看到 CPU 消耗最多的连接。

      【讨论】:

        【解决方案4】:

        相关子查询通常很慢,并且在您尝试提高性能时绝不应该使用。如果需要,使用 fn_split 创建一个临时表索引它,然后加入它以获得您需要的值。您可能需要多次加入以获得不同的价值,而实际上并不知道我很难可视化的数据。

        使用 OR 也不利于性能。请改为在派生表中使用 UNION ALL。

        由于您在视图 rvw_FinancialLineItems 上拥有所有这些条件,是的,将它们拉出到临时表然后索引临时表可能会起作用。

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-05-26
          • 2016-09-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多