变量求和_sql server 2012之,累计求和六种算法效率比较

605d644e07948f44e2b232a337dcf7be.png
/*
需求:累计求和六种算法效率比较
作者:felix
日期:2020-06-23

*/
--第一步,准备测试数据
--IF OBJECT_ID(N'dbo.t') IS NOT NULL
--	DROP TABLE dbo.t;
--GO
--CREATE TABLE dbo.t
--(
--	i BIGINT IDENTITY(1, 1) PRIMARY KEY,
--	d MONEY
--);
--INSERT t
--(
--	d
--)
--SELECT TOP 31465
--	   ROUND(10000 * RAND(CHECKSUM(NEWID())), 2)
--FROM sys.all_objects AS a
--	CROSS JOIN sys.all_objects;

----第二步,创建记录时间的表格
--IF OBJECT_ID(N'dbo.record_time') IS NOT NULL
--	DROP TABLE dbo.record_time;
--GO
--CREATE TABLE dbo.record_time
--(
--	i INT IDENTITY PRIMARY KEY,
--	算法 NVARCHAR(10),
--	bt DATETIME2,--开始时间
--	et DATETIME2,--结束时间
--	idiff AS DATEDIFF(ms, bt, et)--所用的毫秒数
--);
--第一种方法,自连接法,sql server 2008以上版本测试通过,157255661.40
SET STATISTICS TIME OFF;
SET STATISTICS IO OFF;
GO
DECLARE @bt DATETIME2 = GETDATE();
SELECT a.i,
       a.d,
       SUM(b.d) AS total_sum
FROM dbo.t AS a
    INNER JOIN dbo.t AS b
        ON b.i <= a.i
GROUP BY a.i,
         a.d;
DECLARE @et DATETIME2 = GETDATE();
INSERT INTO dbo.record_time
(
    算法,
    bt,
    et
)
VALUES
('自连接', @bt, @et);
--ORDER BY a.i;
GO
;
--第二种方法,递归,sql server 2008以上版本测试通过,157255661.40
DECLARE @bt DATETIME2 = GETDATE();
WITH cte_total_sum
AS (SELECT i,
           d,
           d AS total_sum
    FROM dbo.t
    WHERE i = 1
    UNION ALL
    SELECT s.i,
           s.d,
           p.total_sum + s.d AS total_sum
    FROM dbo.t AS s
        INNER JOIN cte_total_sum AS p
            ON s.i - 1 = p.i)
SELECT *
FROM cte_total_sum
OPTION (MAXRECURSION 0);
DECLARE @et DATETIME2 = GETDATE();
INSERT INTO dbo.record_time
(
    算法,
    bt,
    et
)
VALUES
('递归', @bt, @et);
GO
--第三种方法,over 子句,sql server 2012测试通过,sql server 2008不支持,157255661.40
DECLARE @bt DATETIME2 = GETDATE();

SELECT i,
       d,
       SUM(d) OVER (ORDER BY i) AS total_sum
FROM dbo.t;
DECLARE @et DATETIME2 = GETDATE();

INSERT INTO dbo.record_time
(
    算法,
    bt,
    et
)
VALUES
('over子句', @bt, @et);
GO
--第四种,相关子查询,sql server 2008以上版本测试通过,156625045.22
DECLARE @bt DATETIME2 = GETDATE();
SELECT outquery.i,
       outquery.d,
       (
           SELECT SUM(innerq.d) FROM dbo.t AS innerq WHERE innerq.i <= outquery.i
       ) AS ct --内部查询
FROM dbo.t AS outquery;
DECLARE @et DATETIME2 = GETDATE();
INSERT INTO dbo.record_time
(
    算法,
    bt,
    et
)
VALUES
('相关子查询', @bt, @et);
--ORDER BY outquery.i; --外部查询
GO
--游标方法,有两种方法可以实现,一种是临时表更新,一种是变量叠加更新,157255661.40
--先增加一个存储累计和的列
--第5种,游标_临时表更新
--ALTER TABLE dbo.t ADD total_d MONEY DEFAULT (0);--只运行一次
GO
DECLARE @bt DATETIME2 = GETDATE();
DECLARE @t TABLE --定义表变量,存储累计求和临时结果
(
    i INT PRIMARY KEY IDENTITY,
    d MONEY,
    total_d MONEY
);

DECLARE @i INT = 0,
        @d MONEY = 0,
        @total_d MONEY = 0;
DECLARE c1 CURSOR FOR SELECT i, d FROM dbo.t ORDER BY i;
OPEN c1;
FETCH c1
INTO @i,
     @d;
WHILE @@FETCH_STATUS = 0
BEGIN
    SET @total_d += @d;
    INSERT INTO @t
    (
        d,
        total_d
    )
    VALUES
    (@d, @total_d);
    FETCH c1
    INTO @i,
         @d;
END;
CLOSE c1;
DEALLOCATE c1;
UPDATE dbo.t
SET total_d = b.total_d
FROM dbo.t AS a
    INNER JOIN @t AS b
        ON a.i = b.i;
SELECT *
FROM dbo.t;
DECLARE @et DATETIME2 = GETDATE();
INSERT INTO dbo.record_time
(
    算法,
    bt,
    et
)
VALUES
('游标_临时表更新', @bt, @et);
GO
--第6种,游标_变量叠加更新
DECLARE @bt DATETIME2 = GETDATE();
DECLARE @i INT = 0,
        @d MONEY = 0,
        @total_d MONEY = 0;
DECLARE c1 CURSOR FOR SELECT i, d FROM dbo.t; --ORDER BY i;
OPEN c1;
FETCH c1
INTO @i,
     @d;
WHILE @@FETCH_STATUS = 0
BEGIN
    SET @total_d += @d;
    UPDATE dbo.t
    SET total_d = @total_d
    WHERE i = @i;
    FETCH c1
    INTO @i,
         @d;
END;
CLOSE c1;
DEALLOCATE c1;
SELECT *
FROM dbo.t;
DECLARE @et DATETIME2 = GETDATE();
INSERT INTO dbo.record_time
(
    算法,
    bt,
    et
)
VALUES
('游标_变量叠加更新', @bt, @et);

--执行时间 over子句<游标临时表更新<游标变量叠加更新<自连接<相关子查询<递归查询

b35ea658b3752c97137bf94fc1a58e3a.png

f2dab011c83270618cd147322d8ffbc3.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值