Bayangkan Anda memiliki struktur tabel berikut:
LogId | ProductId | FromPositionId | ToPositionId | Date | Quantity
-----------------------------------------------------------------------------------
1 | 123 | 0 | 10002 | 2018-01-01 08:10:22 | 5
2 | 123 | 0 | 10003 | 2018-01-03 15:15:10 | 9
3 | 123 | 10002 | 10004 | 2018-01-07 21:08:56 | 3
4 | 123 | 10004 | 0 | 2018-02-09 10:03:23 | 1
FromPositionId
dan ToPositionId
posisi saham. Beberapa ID posisi: memiliki makna khusus, misalnya 0
. Peristiwa dari atau ke 0
berarti stok dibuat atau dihapus. Dari 0
bisa menjadi stok dari pengiriman dan 0
menjadi pesanan dikirim.
Tabel ini saat ini menampung sekitar 5,5 juta baris. Kami menghitung nilai stok untuk setiap produk dan posisi ke dalam tabel cache pada jadwal menggunakan kueri yang terlihat seperti ini:
WITH t AS
(
SELECT ToPositionId AS PositionId, SUM(Quantity) AS Quantity, ProductId
FROM ProductPositionLog
GROUP BY ToPositionId, ProductId
UNION
SELECT FromPositionId AS PositionId, -SUM(Quantity) AS Quantity, ProductId
FROM ProductPositionLog
GROUP BY FromPositionId, ProductId
)
SELECT t.ProductId, t.PositionId, SUM(t.Quantity) AS Quantity
FROM t
WHERE NOT t.PositionId = 0
GROUP BY t.ProductId, t.PositionId
HAVING SUM(t.Quantity) > 0
Meskipun ini selesai dalam jumlah waktu yang wajar (sekitar 20 detik), saya merasa seperti ini adalah cara yang cukup tidak efisien untuk menghitung nilai persediaan. Kami jarang melakukan apa pun kecuali INSERT
: di tabel ini, tetapi kadang-kadang kami masuk dan menyesuaikan kuantitas atau menghapus baris secara manual karena kesalahan oleh orang-orang yang menghasilkan baris ini.
Saya memiliki ide untuk membuat "pos pemeriksaan" di tabel terpisah, menghitung nilai hingga titik waktu tertentu dan menggunakannya sebagai nilai awal saat membuat tabel cache jumlah stok kami:
ProductId | PositionId | Date | Quantity
-------------------------------------------------------
123 | 10002 | 2018-01-07 21:08:56 | 2
Fakta bahwa kadang-kadang kita mengubah baris menimbulkan masalah, dalam hal ini kita juga harus ingat untuk menghapus pos pemeriksaan yang dibuat setelah baris log yang kita ubah. Ini dapat diselesaikan dengan tidak menghitung pos pemeriksaan sampai sekarang, tetapi biarkan sebulan antara sekarang dan pos pemeriksaan terakhir (kami sangat jarang melakukan perubahan sejauh itu).
Fakta bahwa kita kadang-kadang perlu mengubah baris sulit untuk dihindari dan saya ingin tetap bisa melakukan ini, itu tidak ditampilkan dalam struktur ini tetapi peristiwa log kadang-kadang terikat dengan catatan lain di tabel lain, dan menambahkan baris log lain untuk mendapatkan jumlah yang tepat terkadang tidak mungkin.
Tabel log, seperti yang Anda bayangkan, tumbuh cukup cepat dan waktu untuk menghitung hanya akan meningkat seiring waktu.
Jadi untuk pertanyaan saya, bagaimana Anda menyelesaikan ini? Apakah ada cara yang lebih efisien untuk menghitung nilai stok saat ini? Apakah ide saya tentang pos pemeriksaan bagus?
Kami menjalankan SQL Server 2014 Web (12.0.5511)
Rencana eksekusi: https://www.brentozar.com/pastetheplan/?id=Bk8gyc68Q
Saya benar-benar memberikan waktu eksekusi yang salah di atas, 20-an adalah waktu yang dibutuhkan untuk menyelesaikan pembaruan cache. Kueri ini membutuhkan sekitar 6-10 detik untuk dijalankan (8 detik ketika saya membuat rencana kueri ini). Ada juga yang bergabung dalam kueri ini yang tidak ada di pertanyaan awal.