Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Разделянето води до текуща заявка за общи суми

Ако не е необходимо да СЪХРАНЯВАТЕ данните (което не трябва, защото трябва да актуализирате текущите суми всеки път, когато някой ред се промени, добави или изтрие) и ако не вярвате на странната актуализация (която вие не трябва, тъй като не е гарантирано, че ще работи и поведението му може да се промени с актуална корекция, сервизен пакет, надстройка или дори промяна на основен индекс или статистика), можете да опитате този тип заявка по време на изпълнение. Това е метод, който колегата MVP Hugo Kornelis измисли „базирана на набор итерация“ (той публикува нещо подобно в една от главите си на Дълбоки гмуркания на SQL Server MVP ). Тъй като текущите суми обикновено изискват курсор върху целия набор, странна актуализация върху целия набор или едно нелинейно самообединяване, което става все по-скъпо с увеличаване на броя на редовете, трикът тук е да преминете през някакъв краен елемент в набора (в този случай, "рангът" на всеки ред по отношение на месец, за всеки потребител - и вие обработвате само всеки ранг веднъж за всички комбинации потребител/месец в този ранг, така че вместо да преминавате през 200 000 реда, завъртате до 24 пъти).

DECLARE @t TABLE
(
  [user_id] INT, 
  [month] TINYINT,
  total DECIMAL(10,1), 
  RunningTotal DECIMAL(10,1), 
  Rnk INT
);

INSERT @t SELECT [user_id], [month], total, total, 
  RANK() OVER (PARTITION BY [user_id] ORDER BY [month]) 
  FROM dbo.my_table;

DECLARE @rnk INT = 1, @rc INT = 1;

WHILE @rc > 0
BEGIN
  SET @rnk += 1;

  UPDATE c SET RunningTotal = p.RunningTotal + c.total
    FROM @t AS c INNER JOIN @t AS p
    ON c.[user_id] = p.[user_id]
    AND p.rnk = @rnk - 1
    AND c.rnk = @rnk;

  SET @rc = @@ROWCOUNT;
END

SELECT [user_id], [month], total, RunningTotal
FROM @t
ORDER BY [user_id], rnk;

Резултати:

user_id  month   total   RunningTotal
-------  -----   -----   ------------
1        1       2.0     2.0
1        2       1.0     3.0
1        3       3.5     6.5 -- I think your calculation is off
2        1       0.5     0.5
2        2       1.5     2.0
2        3       2.0     4.0

Разбира се, че можете актуализирайте основната таблица от тази променлива на таблицата, но защо да се притеснявате, след като тези съхранени стойности са добри само до следващия път, когато таблицата бъде докосната от който и да е DML израз?

UPDATE mt
  SET cumulative_total = t.RunningTotal
  FROM dbo.my_table AS mt
  INNER JOIN @t AS t
  ON mt.[user_id] = t.[user_id]
  AND mt.[month] = t.[month];

Тъй като не разчитаме на имплицитно подреждане от какъвто и да е вид, това се поддържа 100% и заслужава сравнение на производителността в сравнение с неподдържаната странна актуализация. Дори и да не го победи, но да се доближи, все пак трябва да помислите да го използвате, IMHO.

Що се отнася до решението на SQL Server 2012, Мат споменава RANGE но тъй като този метод използва пул на диск, трябва да тествате и с ROWS вместо просто да се изпълнява с RANGE . Ето един бърз пример за вашия случай:

SELECT
  [user_id],
  [month],
  total,
  RunningTotal = SUM(total) OVER 
  (
    PARTITION BY [user_id] 
    ORDER BY [month] ROWS UNBOUNDED PRECEDING
  )
FROM dbo.my_table
ORDER BY [user_id], [month];

Сравнете това с RANGE UNBOUNDED PRECEDING или без ROWS\RANGE изобщо (което също ще използва RANGE макара на диска). Горните ще имат по-ниска обща продължителност и начин по-малко I/O, въпреки че планът изглежда малко по-сложен (допълнителен оператор на проекта за последователност).

Наскоро публикувах публикация в блог, в която се очертават някои разлики в производителността, които наблюдавах за конкретен сценарий за текущи суми:

http://www.sqlperformance.com/2012/07 /t-sql-queries/running-totals



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да архивирате или създадете нова таблица от съществуваща таблица на SQL Server в SQL Server - SQL Server / TSQL урок, част 105

  2. Поддържа ли Microsoft OLE DB доставчик за SQL Server TLS 1.2

  3. Актуализирайте записите в таблицата от CTE

  4. Някакъв начин за вмъкване или актуализиране на SQLBulkCopy, ако съществува?

  5. Премахнете свързан сървър в SQL Server с помощта на T-SQL