कल्पना करें कि आपके पास निम्न तालिका संरचना है:
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
और ToPositionId
स्टॉक पोजीशन हैं। कुछ स्थिति आईडी: उदाहरण के लिए विशेष अर्थ है 0
। एक घटना से या 0
इसका मतलब है कि स्टॉक बनाया या हटा दिया गया था। से 0
और एक वितरण से शेयर किया जा सकता है के लिए 0
एक भेज दिया आदेश हो सकता है।
इस तालिका में वर्तमान में लगभग 5.5 मिलियन पंक्तियाँ हैं। हम प्रत्येक उत्पाद के लिए स्टॉक मूल्य की गणना करते हैं और एक कैश टेबल में एक स्थिति पर एक क्वेरी का उपयोग करते हैं जो कुछ इस तरह दिखता है:
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
भले ही यह उचित समय (लगभग 20 सेकंड) में पूरा हो जाता है, मुझे लगता है कि यह शेयर मूल्यों की गणना का एक बहुत ही अक्षम तरीका है। हम INSERT
इस तालिका में शायद ही कभी कुछ करते हैं : लेकिन हम कभी-कभी अंदर जाते हैं और मात्रा को समायोजित करते हैं या इन पंक्तियों को बनाने वाले लोगों द्वारा गलतियों के कारण मैन्युअल रूप से एक पंक्ति को हटाते हैं।
मेरे पास एक अलग तालिका में "चौकियों" बनाने का विचार था, समय में एक विशिष्ट बिंदु तक मूल्य की गणना करता है और हमारे स्टॉक मात्रा कैश तालिका बनाते समय एक शुरुआती मूल्य के रूप में उपयोग करता है:
ProductId | PositionId | Date | Quantity
-------------------------------------------------------
123 | 10002 | 2018-01-07 21:08:56 | 2
तथ्य यह है कि हम कभी-कभी पंक्तियों को बदलते हैं, इससे समस्या पैदा होती है, उस स्थिति में हमें लॉग पंक्ति को बदलने के बाद बनाई गई किसी भी चेकपॉइंट को हटाने के लिए भी याद रखना चाहिए। यह अब तक चौकियों की गणना नहीं करके हल किया जा सकता है, लेकिन अब और पिछले चेकपॉइंट के बीच एक महीने का समय छोड़ दें (हम बहुत कम ही बदलाव करते हैं जो बहुत दूर हैं)।
तथ्य यह है कि हमें कभी-कभी पंक्तियों को बदलने की आवश्यकता होती है, बचने के लिए कठिन होते हैं और मैं अभी भी ऐसा करने में सक्षम होना चाहता हूं, यह इस संरचना में नहीं दिखाया गया है, लेकिन लॉग इवेंट कभी-कभी अन्य तालिकाओं में अन्य रिकॉर्ड से बंधे होते हैं, और दूसरी लॉग पंक्ति जोड़ते हैं सही मात्रा प्राप्त करने के लिए कभी-कभी संभव नहीं है।
लॉग टेबल है, जैसा कि आप कल्पना कर सकते हैं, बहुत तेजी से बढ़ रहा है और गणना करने का समय केवल समय के साथ बढ़ेगा।
तो मेरे प्रश्न के लिए, आप इसे कैसे हल करेंगे? क्या वर्तमान स्टॉक मूल्य की गणना करने का एक अधिक कुशल तरीका है? क्या चौकियों का मेरा विचार अच्छा है?
हम SQL सर्वर 2014 वेब (12.0.5511) चला रहे हैं
निष्पादन योजना: https://www.brentozar.com/pastetheplan/?id=Bk8gyc68Q
मैंने वास्तव में ऊपर गलत निष्पादन समय दिया, 20 वह समय था जब कैश का पूरा अपडेट लिया गया था। इस क्वेरी को चलाने में लगभग 6-10 सेकंड लगते हैं (जब मैंने यह क्वेरी प्लान बनाया तो 8 सेकंड)। इस प्रश्न में एक जुड़ाव भी है जो मूल प्रश्न में नहीं था।