Cập nhật , nếu bạn đang chạy SQL Server 2012, hãy xem: https://stackoverflow.com/a/10309947
Vấn đề là việc triển khai SQL Server của mệnh đề Over có phần hạn chế .
Oracle (và ANSI-SQL) cho phép bạn làm những việc như:
SELECT somedate, somevalue,
SUM(somevalue) OVER(ORDER BY somedate
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
AS RunningTotal
FROM Table
SQL Server cung cấp cho bạn không có giải pháp rõ ràng cho vấn đề này. Chú ruột của tôi đang nói với tôi rằng đây là một trong những trường hợp hiếm hoi mà con trỏ là nhanh nhất, mặc dù tôi sẽ phải thực hiện một số điểm chuẩn cho kết quả lớn.
Thủ thuật cập nhật rất tiện dụng nhưng tôi cảm thấy nó khá dễ vỡ. Có vẻ như nếu bạn đang cập nhật một bảng đầy đủ thì nó sẽ tiến hành theo thứ tự của khóa chính. Vì vậy, nếu bạn đặt ngày của bạn làm khóa chính tăng dần, bạn sẽ probably
an toàn. Nhưng bạn đang dựa vào một chi tiết triển khai SQL Server không có giấy tờ (cũng như nếu truy vấn kết thúc được thực hiện bởi hai procs tôi tự hỏi điều gì sẽ xảy ra, xem: MAXDOP):
Mẫu làm việc đầy đủ:
drop table #t
create table #t ( ord int primary key, total int, running_total int)
insert #t(ord,total) values (2,20)
-- notice the malicious re-ordering
insert #t(ord,total) values (1,10)
insert #t(ord,total) values (3,10)
insert #t(ord,total) values (4,1)
declare @total int
set @total = 0
update #t set running_total = @total, @total = @total + total
select * from #t
order by ord
ord total running_total
----------- ----------- -------------
1 10 10
2 20 30
3 10 40
4 1 41
Bạn đã yêu cầu một điểm chuẩn đây là mức thấp.
Cách SAFE nhanh nhất để làm điều này sẽ là Con trỏ, nó là một thứ tự có độ lớn nhanh hơn truy vấn phụ tương quan của liên kết chéo.
Cách nhanh nhất tuyệt đối là thủ thuật CẬP NHẬT. Mối quan tâm duy nhất của tôi với nó là tôi không chắc chắn rằng trong mọi trường hợp, việc cập nhật sẽ tiến hành theo cách tuyến tính. Không có gì trong truy vấn nói rõ ràng như vậy.
Dòng dưới cùng, đối với mã sản xuất tôi sẽ đi với con trỏ.
Dữ liệu kiểm tra:
create table #t ( ord int primary key, total int, running_total int)
set nocount on
declare @i int
set @i = 0
begin tran
while @i < 10000
begin
insert #t (ord, total) values (@i, rand() * 100)
set @i = @i +1
end
commit
Kiểm tra 1:
SELECT ord,total,
(SELECT SUM(total)
FROM #t b
WHERE b.ord <= a.ord) AS b
FROM #t a
-- CPU 11731, Reads 154934, Duration 11135
Bài kiểm tra 2:
SELECT a.ord, a.total, SUM(b.total) AS RunningTotal
FROM #t a CROSS JOIN #t b
WHERE (b.ord <= a.ord)
GROUP BY a.ord,a.total
ORDER BY a.ord
-- CPU 16053, Reads 154935, Duration 4647
Bài kiểm tra 3:
DECLARE @TotalTable table(ord int primary key, total int, running_total int)
DECLARE forward_cursor CURSOR FAST_FORWARD
FOR
SELECT ord, total
FROM #t
ORDER BY ord
OPEN forward_cursor
DECLARE @running_total int,
@ord int,
@total int
SET @running_total = 0
FETCH NEXT FROM forward_cursor INTO @ord, @total
WHILE (@@FETCH_STATUS = 0)
BEGIN
SET @running_total = @running_total + @total
INSERT @TotalTable VALUES(@ord, @total, @running_total)
FETCH NEXT FROM forward_cursor INTO @ord, @total
END
CLOSE forward_cursor
DEALLOCATE forward_cursor
SELECT * FROM @TotalTable
-- CPU 359, Reads 30392, Duration 496
Bài kiểm tra 4:
declare @total int
set @total = 0
update #t set running_total = @total, @total = @total + total
select * from #t
-- CPU 0, Reads 58, Duration 139