यह छठी बार है जब मैं यह सवाल पूछना चाह रहा हूं और यह सबसे छोटा है। पिछले सभी प्रयास प्रश्न के बजाय एक ब्लॉग पोस्ट के समान कुछ और थे, लेकिन मैं आपको विश्वास दिलाता हूं कि मेरी समस्या वास्तविक है, यह सिर्फ इतना है कि यह एक बड़े विषय की चिंता करता है और उन सभी विवरणों के बिना जिसमें यह प्रश्न होगा स्पष्ट नहीं है कि मेरी समस्या क्या है। तो यहाँ जाता है ...
सार
मेरे पास एक डेटाबेस है, यह थोड़े फैंसी तरीके से डेटा संग्रहीत करने की अनुमति देता है और कई गैर-मानक सुविधाएं प्रदान करता है जो मेरी व्यवसाय-प्रक्रिया द्वारा आवश्यक हैं। विशेषताएं निम्नलिखित हैं:
- नॉन-डिस्ट्रक्टिव और नॉन-ब्लॉकिंग अपडेट / डिलीट केवल इंसर्ट-एप्रोच के माध्यम से लागू किए जाते हैं, जो डेटा रिकवरी और ऑटोमैटिक लॉगिंग की अनुमति देता है (प्रत्येक परिवर्तन उस बदलाव से जुड़े उपयोगकर्ता से जुड़ा होता है)
- मल्टीवर्सन डेटा (एक ही डेटा के कई संस्करण हो सकते हैं)
- डेटाबेस स्तर की अनुमति
- ACID विनिर्देशन और लेनदेन-सुरक्षित बनाने / अद्यतन / हटाने के साथ अंततः संगति
- समय के किसी भी बिंदु पर डेटा के अपने वर्तमान दृश्य को वापस या तेजी से अग्रेषित करने की क्षमता।
ऐसी अन्य सुविधाएँ हो सकती हैं जिनका मैं उल्लेख करना भूल गया हूँ।
डेटाबेस संरचना
सभी उपयोगकर्ता डेटा Itemsतालिका में JSON एन्कोडेड स्ट्रिंग ( ntext) के रूप में संग्रहीत है । सभी डेटाबेस संचालन दो संग्रहीत प्रक्रियाओं के माध्यम से आयोजित किए जाते हैं GetLatestऔर InsertSnashot, वे डेटा पर काम करने की अनुमति देते हैं कि कैसे जीआईटी स्रोत फ़ाइलों को संचालित करता है।
परिणामी डेटा को पूरी तरह से लिंक किए गए ग्राफ़ में फ्रंट (लिंक्ड) पर जोड़ा गया है, इसलिए अधिकांश मामलों में डेटाबेस क्वेरी बनाने की कोई आवश्यकता नहीं है।
जोंस एन्कोडेड फॉर्म में स्टोर करने के बजाय नियमित एसक्यूएल कॉलम में डेटा स्टोर करना भी संभव है। हालाँकि इससे समग्र जटिलता में वृद्धि होती है।
डेटा पढ़ना
GetLatestनिर्देशों के रूप में डेटा के साथ परिणाम, स्पष्टीकरण के लिए निम्नलिखित आरेख पर विचार करें :
आरेख उन परिवर्तनों का विकास दिखाता है जो कभी एकल रिकॉर्ड में किए गए थे। आरेख पर स्थित तीर संस्करण दिखाते हैं जिसके आधार पर संपादन होता है (कल्पना करें कि उपयोगकर्ता कुछ डेटा ऑफ़लाइन अपडेट कर रहा है, ऑनलाइन उपयोगकर्ता द्वारा किए गए अपडेट के समानांतर, ऐसा मामला संघर्ष का परिचय देगा, जो मूल रूप से डेटा के दो संस्करण हैं। एक के बजाय)।
तो GetLatestनिम्नलिखित इनपुट समय के भीतर कॉल करने के बाद निम्नलिखित रिकॉर्ड संस्करणों के साथ परिणाम होगा:
GetLatest 0, 15 => 1 <= The data is created upon it's first occurance
GetLatest 0, 25 => 2 <= Inserting another version on top of first one overwrites the existing version
GetLatest 0, 30 => 3 <= The overwrite takes place as soon as the data is inserted
GetLatest 0, 45 => 3, 4 <= This is where the conflict is introduced in the system
GetLatest 0, 55 => 4, 5 <= You can still edit all the versions
GetLatest 0, 65 => 4, 6 <= You can still edit all the versions
GetLatest 0, 75 => 4, 6, 7 <= You can also create additional conflicts
GetLatest 0, 85 => 4, 7, 8 <= You can still edit records
GetLatest 0, 95 => 7, 8, 9 <= You can still edit records
GetLatest 0, 105 => 7, 8 <= Inserting a record with `Json` equal to `NULL` means that the record is deleted
GetLatest 0, 115 => 8 <= Deleting the conflicting versions is the only conflict-resolution scenario
GetLatest 0, 125 => 8, X <= The conflict can be based on the version that was already deleted.
GetLatest 0, 135 => 8, Y <= You can delete such version too and both undelete another version on parallel within one Snapshot (or in several Snapshots).
GetLatest 0, 145 => 8 <= You can delete the undeleted versions by inserting NULL.
GetLatest 0, 155 => 8, Z <= You can again undelete twice-deleted versions
GetLatest 0, 165 => 8 <= You can again delete three-times deleted versions
GetLatest 0, 10000 => 8 <= This means that in order to fast-forward view from moment 0 to moment `10000` you just have to expose record 8 to the user.
GetLatest 55, 115 => 8, [Remove 4], [Remove 5] <= At moment 55 there were two versions [4, 5] so in order to fast-forward to moment 115 the user has to delete versions 4 and 5 and introduce version 8. Please note that version 7 is not present in results since at moment 110 it got deleted.
आदेश के लिए में GetLatestइस तरह के कुशल इंटरफ़ेस प्रत्येक रिकॉर्ड विशेष सेवा विशेषताओं को शामिल करना चाहिए समर्थन करने के लिए BranchId, RecoveredOn, CreatedOn, UpdatedOnPrev, UpdatedOnCurr, UpdatedOnNext, UpdatedOnNextIdद्वारा किया जाता है कि GetLatestकि क्या रिकॉर्ड के लिए प्रदान की समयावधि में पर्याप्त रूप से गिर जाता है यह पता लगाने की GetLatestबहस
डेटा सम्मिलित करना
अंतिम स्थिरता, लेनदेन सुरक्षा और प्रदर्शन का समर्थन करने के लिए, डेटा को विशेष मल्टीस्टेज प्रक्रिया के माध्यम से डेटाबेस में डाला जाता है।
डेटा को डेटाबेस में सिर्फ
GetLatestसंग्रहीत कार्यविधि के द्वारा सक्षम किए बिना ही डाला जाता है।डेटा
GetLatestसंग्रहीत प्रक्रिया के लिए उपलब्ध कराया जाता है, डेटा सामान्यीकृत (यानीdenormalized = 0) स्थिति में उपलब्ध कराया जाता है । डेटा सामान्यीकृत राज्य में है, सेवा क्षेत्रोंBranchId,RecoveredOn,CreatedOn,UpdatedOnPrev,UpdatedOnCurr,UpdatedOnNext,UpdatedOnNextIdअभिकलन किया जा रहा है जो वास्तव में धीमी है।चीजों को गति देने के लिए,
GetLatestसंग्रहीत प्रक्रिया के लिए उपलब्ध कराए जाने के साथ ही डेटा को असामान्य किया जा रहा है ।- चूंकि विभिन्न लेन-देन के भीतर किए गए 1,2,3 चरण, यह संभव है कि प्रत्येक ऑपरेशन के बीच में एक हार्डवेयर विफलता हो सकती है। मध्यवर्ती अवस्था में डेटा छोड़ना। ऐसी स्थिति सामान्य है और ऐसा होने पर भी, निम्न
InsertSnapshotकॉल के भीतर डेटा ठीक हो जाएगा । इस भाग का कोडInsertSnapshotसंग्रहीत कार्यविधि के चरण 2 और 3 के बीच पाया जा सकता है ।
- चूंकि विभिन्न लेन-देन के भीतर किए गए 1,2,3 चरण, यह संभव है कि प्रत्येक ऑपरेशन के बीच में एक हार्डवेयर विफलता हो सकती है। मध्यवर्ती अवस्था में डेटा छोड़ना। ऐसी स्थिति सामान्य है और ऐसा होने पर भी, निम्न
समस्या
एक नई सुविधाओं (व्यापार के लिए आवश्यक) मेरे विशेष refactor करने के लिए मजबूर Denormalizerदृश्य जो संबंधों-अप सभी को एक साथ पेश करते हैं और दोनों के लिए प्रयोग किया जाता है GetLatestऔर InsertSnapshot। उसके बाद मैंने प्रदर्शन समस्याओं का सामना करना शुरू कर दिया है। यदि मूल SELECT * FROM Denormalizerरूप से केवल सेकंड के अंशों में निष्पादित किया जाता है तो अब 10000 रिकॉर्ड को संसाधित करने में लगभग 5 मिनट लगते हैं।
मैं DB समर्थक नहीं हूं और मुझे वर्तमान डेटाबेस संरचना के साथ आने में लगभग छह महीने लगे। और मैंने पहले दो हफ्ते बिताए हैं रिफ्लेक्टरिंग करने के लिए और फिर यह पता लगाने की कोशिश कर रहा हूं कि मेरे प्रदर्शन की समस्या का मूल कारण क्या है। मैं अभी नहीं ढूँढ सकता। मैं डेटाबेस बैकअप प्रदान कर रहा हूं (जो आप यहां पा सकते हैं) क्योंकि स्कीमा (सभी अनुक्रमित के साथ) SqlField में फिट होने के लिए बड़ा है, डेटाबेस में अप्रचलित डेटा (10000+ रिकॉर्ड) भी हैं जो मैं परीक्षण उद्देश्यों के लिए उपयोग कर रहा हूं। । इसके अलावा, मैं Denormalizerदेखने के लिए पाठ प्रदान कर रहा हूं जो कि रिफैक्ट हो गया और दर्द से धीमा हो गया:
ALTER VIEW [dbo].[Denormalizer]
AS
WITH Computed AS
(
SELECT currItem.Id,
nextOperation.id AS NextId,
prevOperation.FinishedOn AS PrevComputed,
currOperation.FinishedOn AS CurrComputed,
nextOperation.FinishedOn AS NextComputed
FROM Items currItem
INNER JOIN dbo.Operations AS currOperation ON currItem.OperationId = currOperation.Id
LEFT OUTER JOIN dbo.Items AS prevItem ON currItem.PreviousId = prevItem.Id
LEFT OUTER JOIN dbo.Operations AS prevOperation ON prevItem.OperationId = prevOperation.Id
LEFT OUTER JOIN
(
SELECT MIN(I.id) as id, S.PreviousId, S.FinishedOn
FROM Items I
INNER JOIN
(
SELECT I.PreviousId, MIN(nxt.FinishedOn) AS FinishedOn
FROM dbo.Items I
LEFT OUTER JOIN dbo.Operations AS nxt ON I.OperationId = nxt.Id
GROUP BY I.PreviousId
) AS S ON I.PreviousId = S.PreviousId
GROUP BY S.PreviousId, S.FinishedOn
) AS nextOperation ON nextOperation.PreviousId = currItem.Id
WHERE currOperation.Finished = 1 AND currItem.Denormalized = 0
),
RecursionInitialization AS
(
SELECT currItem.Id,
currItem.PreviousId,
currItem.UUID,
currItem.Json,
currItem.TableName,
currItem.OperationId,
currItem.PermissionId,
currItem.Denormalized,
currItem.Id AS BranchID,
COALESCE (C.PrevComputed, C.CurrComputed) AS CreatedOn,
COALESCE (C.PrevComputed, CAST(0 AS BIGINT)) AS RecoveredOn,
COALESCE (C.PrevComputed, CAST(0 AS BIGINT)) AS UpdatedOnPrev,
C.CurrComputed AS UpdatedOnCurr,
COALESCE (C.NextComputed, CAST(8640000000000000 AS BIGINT)) AS UpdatedOnNext,
C.NextId AS UpdatedOnNextId,
0 AS RecursionLevel
FROM Items AS currItem
INNER JOIN Computed AS C ON currItem.Id = C.Id
WHERE currItem.Denormalized = 0
UNION ALL
SELECT currItem.Id,
currItem.PreviousId,
currItem.UUID,
currItem.Json,
currItem.TableName,
currItem.OperationId,
currItem.PermissionId,
currItem.Denormalized,
currItem.BranchId,
currItem.CreatedOn,
currItem.RecoveredOn,
currItem.UpdatedOnPrev,
currItem.UpdatedOnCurr,
currItem.UpdatedOnNext,
currItem.UpdatedOnNextId,
0 AS RecursionLevel
FROM Items AS currItem
WHERE currItem.Denormalized = 1
),
Recursion AS
(
SELECT *
FROM RecursionInitialization AS currItem
UNION ALL
SELECT currItem.Id,
currItem.PreviousId,
currItem.UUID,
currItem.Json,
currItem.TableName,
currItem.OperationId,
currItem.PermissionId,
currItem.Denormalized,
CASE
WHEN prevItem.UpdatedOnNextId = currItem.Id
THEN prevItem.BranchID
ELSE currItem.Id
END AS BranchID,
prevItem.CreatedOn AS CreatedOn,
CASE
WHEN prevItem.Json IS NULL
THEN CASE
WHEN currItem.Json IS NULL
THEN prevItem.RecoveredOn
ELSE C.CurrComputed
END
ELSE prevItem.RecoveredOn
END AS RecoveredOn,
prevItem.UpdatedOnCurr AS UpdatedOnPrev,
C.CurrComputed AS UpdatedOnCurr,
COALESCE (C.NextComputed, CAST(8640000000000000 AS BIGINT)) AS UpdatedOnNext,
C.NextId,
prevItem.RecursionLevel + 1 AS RecursionLevel
FROM Items currItem
INNER JOIN Computed C ON currItem.Id = C.Id
INNER JOIN Recursion AS prevItem ON currItem.PreviousId = prevItem.Id
WHERE currItem.Denormalized = 0
)
SELECT item.Id,
item.PreviousId,
item.UUID,
item.Json,
item.TableName,
item.OperationId,
item.PermissionId,
item.Denormalized,
item.BranchID,
item.CreatedOn,
item.RecoveredOn,
item.UpdatedOnPrev,
item.UpdatedOnCurr,
item.UpdatedOnNext,
item.UpdatedOnNextId
FROM Recursion AS item
INNER JOIN
(
SELECT Id, MAX(RecursionLevel) AS Recursion
FROM Recursion AS item
GROUP BY Id
) AS nested ON item.Id = nested.Id AND item.RecursionLevel = nested.Recursion
GO
प्रश्न)
वहाँ दो परिदृश्यों को ध्यान में रखा जाता है, जो असामान्य और सामान्यीकृत मामले हैं:
मूल बैकअप की तलाश में, जो
SELECT * FROM Denormalizerइतना दर्दनाक रूप से धीमा कर देता है, मुझे ऐसा लगता है कि डिनायमेलाइज़र दृश्य के पुनरावर्ती भाग के साथ एक समस्या है, मैंने प्रतिबंधितdenormalized = 1लेकिन मेरे कार्यों के गैर-प्रभावित प्रदर्शन को रोकने की कोशिश की है ।चलाने के बाद
UPDATE Items SET Denormalized = 0यह होगाGetLatestऔरSELECT * FROM Denormalizerमें रन धीमी परिदृश्य (मूल रूप से माना जाता), वहाँ गति चीजों को हम सेवा क्षेत्रों परिकलित कर रहे हैं जब लिए एक रास्ता हैBranchId,RecoveredOn,CreatedOn,UpdatedOnPrev,UpdatedOnCurr,UpdatedOnNext,UpdatedOnNextId
पहले ही, आपका बहुत धन्यवाद
पुनश्च
मैं भविष्य के लिए MySQL / Oracle / SQLite जैसे अन्य डेटाबेस को क्वेरी को आसानी से पोर्टेबल बनाने के लिए मानक SQL से चिपके रहने की कोशिश कर रहा हूं, लेकिन अगर कोई मानक sql नहीं है जो डेटाबेस-विशिष्ट निर्माणों से चिपके रहने में मेरी मदद कर सकता है।


