【问题标题】:Low speed SQL query in balance sheet calculation资产负债表计算中的低速SQL查询
【发布时间】:2014-08-10 12:51:31
【问题描述】:

我正在使用Tarazc4 sp计算我的应用程序的资产负债表,但是当我的记录达到50000(超时错误)时非常耗时,请帮忙!我现在想不通了!!!

SELECT * 
INTO #levels
FROM dbo.topics_getlevel()

SELECT * 
INTO #t1 
FROM accounting.documentdetail 
WHERE accounting.documentdetail.date BETWEEN @FromDate AND @ToDate

SELECT * 
FROM 
   (SELECT TOP (100) PERCENT 
        Accounting.Topics.Code, Accounting.Topics.TopicID, Accounting.Topics.ParentID,  
        Accounting.Topics.Description, 
        (SELECT Debit
         FROM dbo.SubTopics_GetSum(Accounting.Topics.TopicID, @FromDate, @ToDate) AS SubTopics_GetSum_2) AS Debit,
        (SELECT Credit
         FROM dbo.SubTopics_GetSum(Accounting.Topics.TopicID, @FromDate, @ToDate) AS SubTopics_GetSum_1) AS Credit, 
        (CASE 
            WHEN ((SELECT     Credit
                              FROM          dbo.subtopics_getsum(Accounting.Topics.TopicID,@FromDate,@ToDate)) -
                          (SELECT     Debit
                             FROM         dbo.subtopics_getsum(Accounting.Topics.TopicID,@FromDate,@ToDate))) < 0 THEN
                          ((SELECT     Debit
                              FROM          dbo.subtopics_getsum(Accounting.Topics.TopicID,@FromDate,@ToDate)) -
                          (SELECT     Credit
                             FROM         dbo.subtopics_getsum(Accounting.Topics.TopicID,@FromDate,@ToDate))) ELSE 0 END) AS ResDEBIT, (CASE WHEN
                          ((SELECT     Credit
                              FROM          dbo.subtopics_getsum(Accounting.Topics.TopicID,@FromDate,@ToDate)) -
                          (SELECT     Debit
                             FROM         dbo.subtopics_getsum(Accounting.Topics.TopicID,@FromDate,@ToDate))) > 0 THEN
                          ((SELECT     Credit
                              FROM          dbo.subtopics_getsum(Accounting.Topics.TopicID,@FromDate,@ToDate)) -
                          (SELECT     Debit
                             FROM         dbo.subtopics_getsum(Accounting.Topics.TopicID,@FromDate,@ToDate))) ELSE 0 END) AS ResCREDIT,(select [Level] from #Levels where TopicID=Accounting.Topics.TopicID) as [Level]
FROM         Accounting.Topics Left OUTER JOIN
                      #t1 ON Accounting.Topics.TopicID = #t1.TopicFK

GROUP BY Accounting.Topics.TopicID, Accounting.Topics.ParentID, Accounting.Topics.Code, Accounting.Topics.Description

ORDER BY Accounting.Topics.TopicID
)
t2

--------------------------------END Tarazc4

并在Tarazc4 sp中使用“dbo.subtopics_getsum”函数来获取每个帐户的总和,请检查一下:

ALTER Function [dbo].[SubTopics_GetSum]

(
@TopicID int,@FromDate char(10),@ToDate char(10)
)
RETURNS TABLE 
AS
RETURN 
(
     WITH cte AS (
     SELECT  T1.TopicID, T1.Code, T1.Description, T1.ParentID, 
     T1.ParentID AS NewParentID, 
     CAST(T1.Code AS nvarchar(MAX)) AS TopicCode, 
     CAST(T1.Description AS nvarchar(MAX)) AS TopicDescription,
     isnull((Accounting.DocumentDetail.Debit),0) AS  Debit,
     isnull((Accounting.DocumentDetail.Credit),0) AS Credit
     FROM Accounting.Topics AS T1 
     LEFT OUTER JOIN
     Accounting.DocumentDetail ON T1.TopicID = Accounting.DocumentDetail.TopicFK
     where (Accounting.DocumentDetail.date between @FromDate and @ToDate) 
     and NOT EXISTS(
          SELECT    T2.TopicID, T2.Code, T2.Description, T2.ParentID, 
          isnull((Accounting.DocumentDetail.Debit),0) AS Debit,
          isnull((Accounting.DocumentDetail.Credit),0) AS Credit
          FROM Accounting.Topics AS T2 
          LEFT OUTER JOIN
          Accounting.DocumentDetail 
          ON T2.TopicID = Accounting.DocumentDetail.TopicFK
          WHERE (Accounting.DocumentDetail.date between @FromDate and @ToDate) 
          and (ParentID = T1.TopicID)
     )
     UNION ALL                          
     SELECT c.TopicID, c.Code, c.Description, c.ParentID, T1.ParentID AS NewParentID, 
     CAST(T1.Code AS nvarchar(MAX)) + c.TopicCode AS TopicCode, 
     CAST(T1.Description AS nvarchar(MAX)) + ' - ' + 
     c.TopicDescription AS TopicDescription,
     c.Debit AS Debit,c.Credit  AS Credit
     FROM cte AS c 
     INNER JOIN Accounting.Topics AS T1 
     ON T1.TopicID = c.NewParentID
     )

     select 
     isnull(sum(Debit),0)+
     isnull(
       (select sum(debit) from accounting.documentdetail 
        where (Accounting.DocumentDetail.date between @FromDate and @ToDate) 
       and topicfk=@TopicID)
     ,0) as Debit,
     isnull(Sum(Credit),0)+
     isnull(
        (select sum(credit) from accounting.documentdetail 
         where (Accounting.DocumentDetail.date between @FromDate and @ToDate) 
         and topicfk=@TopicID)
     ,0) as Credit 
     from cte as c
     WHERE     (NewParentID = @TopicID)
)

实际上,我的主题和文档表如下图所示,我只需要从 documentdetail 表中计算我的主题的资产负债表,并将其显示为我的主题(父子)的层次结构!!!!

【问题讨论】:

  • 唷 - 巨大的混乱代码!只是一般性建议:在查询中使用执行数据库访问的函数通常对性能非常不利......
  • 它真的没什么用——您需要重构代码以不使用该函数,并且还要重构它以不只是在每一列中重复调用该函数。我仍在努力解决这一切。例如,您将文档详细信息转储到 #t1 中,但您不能在函数中使用它。
  • 但是我用那个函数计算每个账户的余额,有什么建议吗?? @marc_s

标签: sql-server-2008 query-performance accounting sqlperformance


【解决方案1】:

我在您的专栏中一遍又一遍地看到dbo.subtopics_getsum(Accounting.Topics.TopicID,@FromDate,@ToDate)。作为一个讨厌的解决方法,您也可以将其转储到像 #t1 这样的临时表中,尽管它可能已经被充分缓存。

我也看不到TOP (100) PERCENT 的必要性,尽管它可能没什么区别。这是在某个阶段从视图中复制出来的吗?

您确实需要正确重构此代码。

【讨论】:

  • 它根本不是复制品,再次检查问题我把我的表格说清楚了,请帮忙
  • 好的,没关系。您知道此查询中 TOP 100 Percent 的实际用途吗?这并不重要,它可能无论如何都不会影响性能。如果您想提高性能,您需要将平衡逻辑从函数中移到查询中。这需要完全重写。
  • 您生成了多少个“主题”?全部/大部分?因为您的功能正在选择一个主题并一遍又一遍地生成该主题。您最好一次性生成所有主题,而不是在重复调用的函数中。
  • 必须生成所有主题,我调用每个主题的函数,因为它应该计算每个主题的孩子余额并将它们的总和返回给父主题。你的意思是如果把getsum代码放在tarazc4里面会提高性能????
  • 如果您删除这些函数(将 getsum 代码移动到 taracz4 中),它很可能会提高性能。但是,如果您有父子关系,则应该只计算叶级值并将它们汇总到父/子层次结构中,这对您的代码来说是一个很大的变化。
【解决方案2】:

最后,我想出了这段代码并惊人地提高了我的性能,但是请检查一下是否还有其他可以帮助提高性能的点???

select * into #tleaf from(select *,(CASE WHEN (Credit-Debit) < 0 THEN (Debit-Credit) ELSE 0 END) AS ResDEBIT,(CASE WHEN(Credit-Debit) > 0 THEN(Credit-Debit) ELSE 0 END) AS ResCREDIT from (SELECT  Accounting.AllTopicsCTE.TopicID, Accounting.AllTopicsCTE.ParentID, Accounting.AllTopicsCTE.Code, Accounting.AllTopicsCTE.Description, isnull(sum(Debit),0) as Debit,isnull(sum(Credit),0) as Credit
                             from Accounting.AllTopicsCTE  LEFT OUTER JOIN
                      Accounting.DocumentDetail ON Accounting.AllTopicsCTE.TopicID = Accounting.DocumentDetail.TopicFK
                      where Accounting.DocumentDetail.Date between @FromDate and @ToDate
                      group by Accounting.AllTopicsCTE.TopicID, Accounting.AllTopicsCTE.ParentID, Accounting.AllTopicsCTE.Code, Accounting.AllTopicsCTE.Description) t0 
                     )t1
               select TopicID,ParentID,Code,Description,0 as Debit,0 as Credit,0 as ResDebit,0 as ResCredit into #tmain from Accounting.Topics where TopicID not in(select TopicID from #tleaf)      

                   --#tresult 
                    select * into #tresult from 
                    (select * from #tmain
                     union all
                     select * from #tleaf) b;
                     --------------------------------------------------------------
WITH HierarchicalCTE AS
(
    SELECT TopicID, ParentID, Code, Description,
           Debit,Credit,ResDebit,ResCredit, 0 AS LEVEL
    FROM #tresult i
    UNION ALL
    SELECT i.TopicID, i.ParentID, i.Code, i.Description,
           cte.Debit, cte.Credit,cte.ResDebit,cte.ResCredit,
           cte.LEVEL + 1
    FROM HierarchicalCTE cte join
         #tresult i
         ON i.TopicID = cte.ParentID
)
select TopicID, ParentID, Code, Description,
       sum(Debit) as Debit, sum(Credit) as Credit,sum(ResDebit) as ResDEBIT,sum(ResCredit) as ResCREDIT,(select [Level] from #Levels where TopicID=HierarchicalCTE.TopicID) as [Level]
from HierarchicalCTE
group by TopicID, ParentID, Code, Description
                     ------------------------------

【讨论】:

  • 我注意到两件事:1. 使用select * 是不好的做法。添加或删除列时会引发错误。 2.您将加入一个表,然后对其进行过滤,从而有效地使其成为内部联接。 可能通过将不需要的外部联接转换为内部联接来提高性能。如您所见,按照我的建议删除该功能可以提高性能。接下来您可能要做的就是获取一个查询计划 (CTRL-L) 并查看它是否建议任何索引。
  • Tahnks 亲爱的@ElectricLlama
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-13
相关资源
最近更新 更多