Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Mempartisi menghasilkan kueri total yang berjalan

Jika Anda tidak perlu MENYIMPAN data (yang seharusnya tidak, karena Anda perlu memperbarui total yang berjalan setiap kali ada baris yang diubah, ditambahkan, atau dihapus), dan jika Anda tidak mempercayai pembaruan unik (yang Anda tidak boleh, karena tidak dijamin berfungsi dan perilakunya dapat berubah dengan perbaikan terbaru, paket layanan, peningkatan, atau bahkan indeks atau perubahan statistik yang mendasarinya), Anda dapat mencoba jenis kueri ini saat runtime. Ini adalah metode sesama MVP Hugo Kornelis menciptakan "iterasi berbasis set" (ia memposting sesuatu yang serupa di salah satu babnya Penyelaman MVP SQL Server ). Karena total yang berjalan biasanya memerlukan kursor di seluruh rangkaian, pembaruan unik di seluruh rangkaian, atau penggabungan mandiri non-linier tunggal yang menjadi semakin mahal seiring bertambahnya jumlah baris, triknya di sini adalah mengulang beberapa yang terbatas elemen dalam set (dalam hal ini, "peringkat" setiap baris dalam istilah bulan, untuk setiap pengguna - dan Anda hanya memproses setiap peringkat satu kali untuk semua kombinasi pengguna/bulan pada peringkat itu, jadi alih-alih mengulang hingga 200.000 baris, Anda mengulang hingga 24 kali).

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;

Hasil:

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

Tentu saja Anda bisa perbarui tabel dasar dari variabel tabel ini, tetapi mengapa repot-repot, karena nilai-nilai yang disimpan itu hanya baik sampai tabel berikutnya disentuh oleh pernyataan 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];

Karena kami tidak mengandalkan pemesanan implisit dalam bentuk apa pun, ini 100% didukung dan layak mendapatkan perbandingan kinerja relatif terhadap pembaruan unik yang tidak didukung. Meskipun tidak mengalahkannya tetapi mendekati, Anda harus tetap mempertimbangkan untuk menggunakannya IMHO.

Adapun solusi SQL Server 2012, Matt menyebutkan RANGE tetapi karena metode ini menggunakan spool pada disk, Anda juga harus menguji dengan ROWS daripada hanya menjalankan dengan RANGE . Berikut adalah contoh cepat untuk kasus Anda:

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];

Bandingkan dengan RANGE UNBOUNDED PRECEDING atau tidak ada ROWS\RANGE sama sekali (yang juga akan menggunakan RANGE gulungan pada disk). Di atas akan memiliki durasi keseluruhan yang lebih rendah dan cara lebih sedikit I/O, meskipun rencananya terlihat sedikit lebih kompleks (operator proyek urutan tambahan).

Saya baru-baru ini menerbitkan posting blog yang menguraikan beberapa perbedaan kinerja yang saya amati untuk skenario total berjalan tertentu:

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. .NET 4:Cara mengkonfigurasi file EDMX di rakitan lain di Web.Config

  2. 3 Cara Mendapatkan Skema Hasil yang Ditetapkan di SQL Server

  3. Cara Memisahkan String di SQL Server

  4. Memilih dan Mengonfigurasi Perangkat Keras untuk SQL Server 2016 Edisi Standar

  5. Bagaimana cara menghitung perbedaan jam (desimal) antara dua tanggal di SQL Server?