2

我检查过类似的问题,但没有一个对我有用。最有用的是http://forums.asp.net/t/1170815.aspx/1,但性能使我的查询运行了几个小时。

我有 150 万条记录,基于 4 年的产品销售(约 10k 产品)。我想要一个包含日期、产品和滚动十二个月销售额的表格。

此查询(来自上面的链接)有效,并显示了我想要的内容,但性能使其无用:

select day_key, product_key, price, (select sum(price) as R12 from #ORDER_TURNOVER as tb1 where tb1.day_key <= a.day_key and tb1.day_key > dateadd(mm, -12, a.day_key) and tb1.product_key = a.product_key) as RSum into #hejsan
from #ORDER_TURNOVER as a

我为所有记录尝试了一个滚动求和游标函数,它快如闪电,但我无法获得仅对过去 365 天的销售额求和的查询。

非常感谢有关如何解决此问题的任何想法。谢谢你。

4

2 回答 2

4

我会稍微改变你的设置。

首先,有一个表格,列出所有感兴趣的产品密钥......

CREATE TABLE product (
  product_key    INT NOT NULL,
  price          INT,
  some_fact_data VARCHAR(MAX),
  what_ever_else SOMEDATATYPE,
  PRIMARY KEY CLUSTERED (product_key)
)

然后,我会有一个日历表,其中包含您可能需要报告的每个日期......

CREATE TABLE calendar (
  date             SMALLDATETIME,
  is_bank_holdiday INT,
  what_ever_else   SOMEDATATYPE,
  PRIMARY KEY CLUSTERED (date)
)

最后,我会确保您的数据表在所有相关字段上都有一个覆盖索引......

CREATE INDEX IX_product_day ON #ORDER_TURNOVER (product_key, day_key)

这将允许以下查询...

SELECT
  product.product_key,
  product.price,
  calendar.date,
  SUM(price)    AS RSum
FROM
  product
CROSS JOIN
  calendar
INNER JOIN
  #ORDER_TURNOVER AS data
    ON  data.product_key = product.product_key
    AND data.day_key    >  dateadd(mm, -12, calendar.date)
    AND data.day_key    <= calendare.date
GROUP BY
  product.product_key,
  product.price,
  calendar.date

通过以这种方式执行所有操作,每个 product/calendar_date 组合将与数据表中的一组记录相关,这些记录彼此连续。对于优化器来说,这将使查找要聚合的数据的行为变得更加简单。

[需要一个索引,特别是在顺序(产品、日期)中。]

如果你有相反的索引,它实际上要困难得多......

示例数据:

 product | date                   date | product
---------+-------------    ------------+---------
    A    |  01/01/2012      01/01/2012 |    A
    A    |  02/01/2012      01/01/2012 |    B
    A    |  03/01/2012      02/01/2012 |    A
    B    |  01/01/2012      02/01/2012 |    B
    B    |  02/01/2012      03/01/2012 |    A
    B    |  03/01/2012      03/01/2012 |    B

在左侧 oyu 中,只需获取 365 天块中彼此相邻的所有记录。

在右侧搜索每条记录,然后才能进行聚合。搜索相对简单,但你做了 365 个。比左边的版本要多得多。

于 2012-05-22T12:51:53.200 回答
1

这就是 SQL Server 2005-2008 中“运行总计”/“汇总子集”的方式。在 SQL 2012 中,原生支持运行总计,但我们仍在使用 2005-2008 db

SELECT  day_key ,
        product_key ,
        price ,
        ( SELECT    SUM(price) AS R12
          FROM      #ORDER_TURNOVER AS tb1
          WHERE     tb1.day_key <= a.day_key
                    AND tb1.day_key > DATEADD(mm, -12, a.day_key)
                    AND tb1.product_key = a.product_key
        ) AS RSum
INTO    #hejsan
FROM    #ORDER_TURNOVER AS a 

几点建议。

您可以预先计算运行总计,这样就不会一次又一次地计算它们。你在做什么上面的选择是一个变相的循环而不是一个集合查询(除非优化器可以将子查询转换为连接)。

上述解决方案需要对代码进行一些更改。

您当然可以尝试的另一个解决方案是在 #ORDER_TURNOVER 临时表上创建一个聚集索引。这更安全,因为它是本地更改。

CREATE CLUSTERED INDEX IndexName
ON #ORDER_TURNOVER (day_key,day_key,product_key)

WHERE 子句中的所有 3 个表达式都是 SARGS,因此优化器现在将执行搜索而不是扫描。

如果索引解决方案没有提供足够的性能提升,那么值得投资解决方案 1

于 2012-05-22T12:36:40.817 回答