【问题标题】:Long Execution Time for Cumulative Sum in SQL Server 2008SQL Server 2008 中累积和的长执行时间
【发布时间】:2015-06-02 18:17:29
【问题描述】:

我使用 SQL Server 2008 处理 C# 项目。

在我的项目中,我想通过 SQL 语句获取一些记录:

WITH tbl_tmp
AS (
    SELECT TOP 100 PERCENT 
        ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS row
        ,d.doc_amount AS amount
    FROM docs AS d
    LEFT OUTER JOIN docs_items AS di ON di.doc_id = d.doc_id
    WHERE di.branch_id = 1
        AND di.doc_date >= 20150101
        AND di.doc_date <= 20151201
        AND SUBSTRING(CAST(d.acc_id AS VARCHAR), 1, 4) = 1130
    ORDER BY di.doc_date ASC
        ,di.doc_number ASC
        ,d.docrow ASC
    )

SELECT row,
       amount,
       (
        SELECT CASE 
                WHEN (SUM(amount)) < 0
                    THEN ABS(SUM(amount))
                ELSE 0
                END
        FROM tbl_tmp AS _tmp
        WHERE _tmp.row <= tbl_tmp.row
        ) AS sum_debtor
    ,(
        SELECT CASE 
                WHEN (SUM(amount)) > 0
                    THEN ABS(SUM(amount))
                ELSE 0
                END
        FROM tbl_tmp AS _tmp
        WHERE _tmp.row <= tbl_tmp.row
        ) AS sum_creditor
FROM tbl_tmp;

但是从 SQL Server 获取记录的执行时间很长(例如获取 2207 条记录需要 28 秒,而我的 PC 是 Core-i7 & 8Gb Ram)

如何在更快的时间内获得结果?

PS:即使我从 SQL 语句中删除了 «sum_creditor 列»,对于 2207 条记录,我的执行时间还是 14 秒,这对我来说太长了。


编辑:

我的输出结果是这样的:

row    |amount      |sum_debtor     |sum_debtor
-------------------------------------------------
1      |1000        |1000           |0
2      |500         |1500           |0
3      |-2500       |0              |1000
4      |6000        |5000           |0
5      |-3000       |2000           |0 
.
.
.
.
2206   |8000        |13000          |0
2207   |-20000      |0              |7000 

【问题讨论】:

  • 您真的要在 12 月 1 日或 12 月 31 日结束搜索吗? di.doc_date
  • 我像 yyyymmdd 这样存储日期,有什么不同?问题是别的。
  • 我的意思是,您的标准在 12 月 1 日结束。通常开始日期是 1 月 1 日,结束日期是 12 月 31 日 :)

标签: sql-server cumulative-sum sqlperformance


【解决方案1】:

需要考虑的几点:

  • SELECT TOP 100 PERCENT 是不必要的。如果要选择所有记录,只需执行SELECT。查询优化器应该足够聪明,可以忽略这一点,但你永远不知道
  • 我在这里做了一些假设,因为您没有列出任何示例数据,但看起来 CTE 只提取了一个行号和一个数量。然后看起来你想要提取两个计数,债务人和债权人,其中每个负数是债务人计数,每个正数是债权人。如果是这种情况,则不需要嵌套两个 SELECTs,CTE 中的 ROW_NUMBER() 也是如此。如果我的假设是正确的,我敢打赌_tmp.row &lt;= tbl_tmp.row 绝对会扼杀你的表现。像这样的东西应该会给你你正在寻找的东西:

    SELECT 
        SUM(CASE WHEN amount < 0 THEN 1 ELSE 0 END) debtor
        , SUM(CASE WHEN amount > 0 THEN 1 ELSE 0 END) creditor
    FROM tbl_tmp
    
  • 您的问题已标记为 SQL Server。如果是这种情况,您的计算机速度与查询执行时间无关。从服务器返回结果所需的时间完全取决于 SQL Server 的性能(硬件、可用资源、竞争 TSQL 查询、适用的索引及其碎片等)。您的计算机将查询发送到服务器,然后在服务器发送响应之前什么都不做。拥有世界上最快的台式计算机不会让您的查询执行得更快(除非您在本地计算机上运行 Express 实例)。

【讨论】:

  • 谢谢,1- 我在 tbl_tmp 中排序最多的列,所以我最常使用 TOP 100 PERCENT 语句,因为没有这个 SQL 服务器会显示此错误:The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP or FOR XML is also specified. 2- 我使用 _tmp.row &lt;= tbl_tmp.row 因为我想要累积总和或运行总和,而不是常规总和,有关累积总和的更多信息,请参阅:mathsisfun.com/data/cumulative-tables-graphs.html 3- 是的,我使用的是 express 版本和安装在本地计算机上的 SQL 服务器,
  • 我明白了。由于使用了债务人和债权人,我误解了您的意思。我将编辑我的示例。您的一些源数据的示例以及您的预期输出对于回答这个问题仍然非常有帮助。
  • 我编辑了我的问题并添加了输出记录示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-28
  • 2021-01-15
  • 2021-09-30
  • 2023-03-15
  • 1970-01-01
相关资源
最近更新 更多