sql - 根据今年今天、本周、本月、本季度汇总销售额的最快方法?

标签 sql sql-server tsql aggregate-functions

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

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

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%。

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

最佳答案

由于现在是星期五下午,我想我应该扩展一下有关仓储的评论。即使您无法使用 SSAS 或任何其他 OLAP 完全探索多维数据集,您仍然可以进行自己的特定于报告的仓储。在你的情况下,我将建立一个新的数据库(我总是称我的DW,但世界是你的牡蛎),并创建2个模式Fact和Dim(代表事实和维度)。在您的情况下,它需要 2 个表,但您可能希望为“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

它看起来比原始查询更复杂,但在线数据库增长得越多,您就会看到更多的好处。我已经做了SQL Fiddle为了展示其优势,它用 10000 条随机销售记录填充实时数据,然后创建一个仓库(构建架构可能需要几秒钟)。您应该注意到仓库上查询的执行时间显着加快 (c.20x)。第一次运行时可能不会快 20 倍,但是一旦为两个查询缓存了查询计划,仓库查询就会始终快 20 倍(无论如何对我来说都是如此)。

关于sql - 根据今年今天、本周、本月、本季度汇总销售额的最快方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10352621/

相关文章:

mysql - 比较一个查询中两个不同的查询输出

sql - 如果任何字段匹配,如何对 postgres 表的结果进行分组?

SQL Server 2008 R2 计算字段问题

sql - 数据库 [dbName] 不可访问。 (对象资源管理器)

sql - 如何根据另一个表中另一列的值更新列?

MySql 获取余额查询

mysql - 具有子查询的 PROCEDURE 中的 CURSOR

mysql - SQL Server 到 MySQL 数据传输

sql-server - 识别存储过程是否存在的首选方法是什么

sql-server - 如何从计数不同的查询中过滤掉