Sql 根据今天、本周、本月、本季度总结销售额的最快方法?

Sql 根据今天、本周、本月、本季度总结销售额的最快方法?,sql,sql-server,tsql,aggregate-functions,Sql,Sql Server,Tsql,Aggregate Functions,下面的查询返回正确的结果,但如何更快地获得相同的结果 目标是通过总结今天、本周、本月和本季度的销售额,输出一个跟踪卖家进度的表格 SellerID Today ThisWeek ThisMonth ThisQuarter ----------- --------------------- --------------------- --------------------- -----------------

下面的查询返回正确的结果,但如何更快地获得相同的结果

目标是通过总结今天、本周、本月和本季度的销售额,输出一个跟踪卖家进度的表格

SellerID    Today                 ThisWeek              ThisMonth             ThisQuarter
----------- --------------------- --------------------- --------------------- ---------------------
1           400,00                700,00                900,00                900,00
2           950,00                1850,00               2650,00               2650,00
我的问题是:

CREATE TABLE #sales(
    [Price] MONEY,
    [Date] DATE,
    [SellerID] INT
)

INSERT INTO #sales VALUES 
(100, '2012-01-01', 1),
(200, '2012-04-01',1),
(300, '2012-04-23',1),
(400, '2012-04-27',1),
(700, '2012-01-01', 2),
(700, '2012-01-02', 2),
(800, '2012-04-01',2),
(900, '2012-04-23',2),
(950, '2012-04-27',2)


SELECT 
SellerID AS SellerID,

SUM(CASE WHEN [Date] >= DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()),0) THEN [Price] END) AS Today,
SUM(CASE WHEN [Date] >= DATEADD(WEEK, DATEDIFF(WEEK, 0, GETDATE()), 0) THEN [Price] END) AS ThisWeek,
SUM(CASE WHEN [Date] >= DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0) THEN [Price] END) AS ThisMonth,
SUM(CASE WHEN [Date] >= DATEADD(QUARTER, DATEDIFF(QUARTER, 0, GETDATE()), 0) THEN [Price] END) AS ThisQuarter

FROM #sales
WHERE DATEPART(YEAR, [Date]) = DATEPART(YEAR, GETDATE()) 
GROUP BY SellerID
在较大的表上执行相同的查询时,速度会非常慢。仅仅删除CASE语句就可以将执行时间缩短近50%


如何以更快、更高效的方式实现相同的结果?

保留数据的非标准化版本

e、 g:

然后可以运行如下查询:

select 
    year
    ,sum(price)
from 
    deNormalised
where 
    quarter = 1
group by 
    year
来比较不同年份的第一季度

显然,这意味着您必须制定一个时间表来维护数据的非标准化版本。您可以在更新时使用触发器或每小时执行一次

您还可以尝试将最新数据添加到非标准化结果中。。这样,您只需对今天创建的行执行缓慢的处理


编辑:我不知道仅仅使用DATENAME函数是否会提高使用现有结构的性能。

因为现在是星期五下午,我想我应该进一步谈谈我对仓储的看法。即使您无法使用SSA或任何其他OLAP完全浏览多维数据集,您仍然可以自己进行特定于报表的存储。在您的情况下,我将建立一个新的数据库(我总是称我的DW,但世界是您的牡蛎),并创建两个模式Fact和Dim(表示事实和维度)。在您的情况下,它将需要两个表,尽管您可能希望为“SellerID”添加另一个维度,这取决于是否需要进一步报告

CREATE TABLE Dim.Date
(       DateKey     DATE NOT NULL,
        DayOfWeek   VARCHAR(20) NOT NULL,
        Day         TINYINT NOT NULL,
        Week        TINYINT NOT NULL,
        Quarter     TINYINT NOT NULL,
        Month       TINYINT NOT NULL,
        Year        SMALLINT NOT NULL
    CONSTRAINT PK_Dim_Date_DateKey PRIMARY KEY (DateKey)
)
CREATE TABLE Fact.Sales
(       DateKey     DATE NOT NULL,
        SellerID    INT NOT NULL,
        Sales       INT NOT NULL,
        Amount      MONEY NOT NULL,
    CONSTRAINT PK_Fact_Sales PRIMARY KEY (DateKey, SellerID),
    CONSTRAINT FK_Fact_Sales_DateKey FOREIGN KEY (DateKey) REFERENCES Dim.Date
)
假设数据不会被回溯,您可以使用这样的过程在计划作业中填充仓库:

DECLARE @MaxDate DATE
SELECT  @MaxDate = DATEADD(DAY, 1, MAX(DateKey))
FROM    Fact.Sales

INSERT INTO Dim.Date
SELECT  DATEADD(DAY, Increment, @MaxDate), 
        DATENAME(WEEKDAY, DATEADD(DAY, Increment, @MaxDate)), 
        DATEPART(DAY, DATEADD(DAY, Increment, @MaxDate)),
        DATEPART(WEEK, DATEADD(DAY, Increment, @MaxDate)),
        DATEPART(MONTH, DATEADD(DAY, Increment, @MaxDate)),
        DATEPART(QUARTER, DATEADD(DAY, Increment, @MaxDate)),
        DATEPART(YEAR, DATEADD(DAY, Increment, @MaxDate))
FROM    (   SELECT  ROW_NUMBER() OVER(ORDER BY Object_ID) - 1 [Increment]
            FROM    Sys.Objects
        ) obj
WHERE   NOT EXISTS
        (   SELECT  1
            FROM    Dim.Date
            WHERE   Date.DateKey = DATEADD(DAY, Increment, @MaxDate)
        )


INSERT INTO Fact.Sales
SELECT  [Date], SellerID, COUNT(*), SUM(Price)
FROM    LiveDatabase..Sales
WHERE   [Date] >= @MaxDate
GROUP BY [Date], SellerID
这将留给您以下查询以生成报告

SELECT  SellerID,
        SUM(CASE WHEN Today.DateKey = Date.DateKey THEN Amount ELSE O END) [Today],
        SUM(CASE WHEN Today.Week = Date.Week THEN Amount ELSE O END) [ThisWeek],
        SUM(CASE WHEN Today.Month = Date.Month THEN Amount ELSE O END) [ThisMonth],
        SUM(CASE WHEN Today.Quarter = Date.Quarter THEN Amount ELSE O END) [ThisQuarter],
        SUM(CASE WHEN Today.Year = Date.Year THEN Amount ELSE O END) [ThisYear]
FROM    Fact.Sales
        INNER JOIN Dim.Date
            ON Date.DateKey = Sales.DateKey
        INNER JOIN Dim.Date Today
            ON Today.DateKey = CAST(GETDATE() AS DATE)
            AND Today.Year = Date.Year
GROUP BY SellerID

如果说有什么区别的话,它看起来比原始查询更复杂,但是在线数据库增长得越多,您就会看到更多的好处。我做了一个示例来演示其优点,它用10000条随机销售记录填充实时数据,然后创建一个仓库(构建模式可能需要几秒钟)。您应该注意到在仓库上执行查询的时间要快得多(c.20x)。第一次运行时可能不会快20倍,但一旦两个查询都缓存了查询计划,仓库查询就会一直快20倍(对我来说也是如此)。

这是一个很好的解决方案。事实上,今天我们正在为一些数据创建非规范化版本。这些数据经常被更新和访问,因此最简单的方法可能是在web前端使用缓存,以防止对每个请求执行缓存?同样,缓存web请求的简单版本仅适用于相同的参数。。非规范化的数据在所有查询中都会表现得更好。我不是专家,也没有在任何大型应用程序上实践过这一点,因此可能一些具有更多真实世界经验的人会给出一些答案。谢谢你的建议。我认为GarethD下一步探索数据仓库是正确的。是的,这是一个非常好的主意,我从未做过,但我与顾问一起工作过,他们用立方体等做了一些非常惊人的事情。我的解决方案就像穷人的版本;-)而且,只要您的
[Date]
列被编入索引,您甚至可能已经拥有了许可证中的组件。我认为您已经拥有查询事务数据的最有效解决方案。如果您遇到性能问题,您可能希望导出数据仓库。是的,它已编制索引。我们使用的是SQLAzure,不幸的是目前它有点有限。我也认为这将是一个更好的方法(+1)。有一些答案!谢谢加雷斯!
SELECT  SellerID,
        SUM(CASE WHEN Today.DateKey = Date.DateKey THEN Amount ELSE O END) [Today],
        SUM(CASE WHEN Today.Week = Date.Week THEN Amount ELSE O END) [ThisWeek],
        SUM(CASE WHEN Today.Month = Date.Month THEN Amount ELSE O END) [ThisMonth],
        SUM(CASE WHEN Today.Quarter = Date.Quarter THEN Amount ELSE O END) [ThisQuarter],
        SUM(CASE WHEN Today.Year = Date.Year THEN Amount ELSE O END) [ThisYear]
FROM    Fact.Sales
        INNER JOIN Dim.Date
            ON Date.DateKey = Sales.DateKey
        INNER JOIN Dim.Date Today
            ON Today.DateKey = CAST(GETDATE() AS DATE)
            AND Today.Year = Date.Year
GROUP BY SellerID
select 
     SellerID
    ,sum(case when [Date]=getdate() then [Price] else 0 end) as Today
    ,sum(case when datepart(week,[Date])=datepart(week,getdate()) then [Price] else 0 end) as ThisWeek
    ,sum(case when datepart(MONTH,[Date])=datepart(month,getdate()) then [Price] else 0 end) as ThisMonth
    ,sum(case when datepart(QUARTER,[Date])=datepart(QUARTER,getdate()) then [Price] else 0 end) as ThisQUARTER
from #sales
Group by SellerID