हटाए गए उपयोगकर्ताओं को संभालना - अलग या एक ही तालिका?


19

परिदृश्य यह है कि मुझे उपयोगकर्ताओं का एक विस्तृत सेट मिला है, और जैसे-जैसे समय बीतता जाएगा, उपयोगकर्ता अपने खाते रद्द कर देंगे, जिन्हें हम वर्तमान में एक ही तालिका में 'हटाए गए' (एक ध्वज के साथ) के रूप में चिह्नित करते हैं।

यदि एक ही ईमेल पते वाले उपयोगकर्ता (जो उपयोगकर्ता लॉग इन करते हैं) एक नया खाता बनाना चाहते हैं, तो वे फिर से साइन अप कर सकते हैं, लेकिन एक नया खाता बनाया जाता है। (हमारे पास प्रत्येक खाते के लिए अद्वितीय आईडी हैं, इसलिए ईमेल पते को लाइव और हटाए गए लोगों के बीच दोहराया जा सकता है)।

मैंने जो देखा है वह यह है कि हमारे पूरे सिस्टम में, सामान्य चीजों में, जो हम लगातार पूछते हैं कि उपयोगकर्ता टेबल की जाँच कर रहा है, उपयोगकर्ता नष्ट नहीं होता है, जबकि मैं जो सोच रहा हूं, वह यह है कि हमें ऐसा करने की आवश्यकता नहीं है ... ! [Clarification1: 'लगातार क्वेरी' द्वारा, मेरा मतलब है कि हमारे पास ऐसे प्रश्न हैं जो इस तरह हैं: '... उपयोगकर्ताओं से जहां = "0" और ...'। उदाहरण के लिए, हमें किसी विशेष तिथि पर सभी बैठकों के लिए पंजीकृत सभी उपयोगकर्ताओं को लाने की आवश्यकता हो सकती है, इसलिए इस प्रश्न में, हमारे पास उपयोगकर्ताओं से भी है जहां = "0" - क्या यह मेरी बात को स्पष्ट करता है?]

(1) continue keeping deleted users in the 'main' users table
(2) keep deleted users in a separate table (mostly required for historical
    book-keeping)

किसी भी दृष्टिकोण के पेशेवरों और विपक्ष क्या हैं?


आप किन कारणों से उपयोगकर्ताओं को रखते हैं?
कीपला

2
इसे सॉफ्ट-डिलीट कहा जाता है। डिलीट डेटाबेस रिकॉर्ड्स
Sjoerd

@keppla - उनका उल्लेख है कि: "ऐतिहासिक पुस्तक-लेखन"।
ChrisF

@ क्रिस: मुझे इस क्षेत्र में दिलचस्पी थी: क्या वह केवल उपयोगकर्ताओं की पुस्तकें रखना चाहता है, या अभी भी कुछ डेटा संलग्न है (ईजी टिप्पणी, भुगतान, आदि)
कीपला

यह उन्हें हटाने के रूप में सोचना बंद कर सकता है (जो सत्य नहीं है) और उनके खाते को रद्द (जो सत्य है) के रूप में सोचना शुरू कर सकता है
माइक शेरिल 'कैट रिकॉल'

जवाबों:


13

(1) 'मुख्य' उपयोगकर्ता तालिका में हटाए गए उपयोगकर्ताओं को जारी रखना

  • पेशेवरों: सभी मामलों में सरल प्रश्न
  • विपक्ष: यदि उपयोगकर्ताओं की अधिक संख्या है, तो समय के साथ प्रदर्शन को कम कर सकते हैं

(2) हटाए गए उपयोगकर्ताओं को एक अलग तालिका में रखें (ज्यादातर ऐतिहासिक पुस्तक-रखने के लिए आवश्यक)

आप हटाए गए उपयोगकर्ताओं को इतिहास तालिका में स्वचालित रूप से स्थानांतरित करने के लिए एक ट्रिगर जैसे उदाहरण का उपयोग कर सकते हैं।

  • पेशेवरों: सक्रिय उपयोगकर्ता तालिका, स्थिर प्रदर्शन के लिए सरल रखरखाव
  • विपक्ष: इतिहास तालिका के लिए विभिन्न प्रश्नों की आवश्यकता है; हालाँकि, अधिकांश ऐप में दिलचस्पी नहीं है, यह नकारात्मक प्रभाव शायद सीमित है

11
एक विभाजन तालिका (IsDeleted पर) एकल तालिका का उपयोग करने के साथ प्रदर्शन समस्याओं को दूर करेगी।
इयान

1
@ जब तक प्रत्येक क्वेरी को IsDeleted के साथ क्वेरी मानदंड के रूप में प्रदान नहीं किया जाता है (जो मूल प्रश्न में नहीं लगता है), विभाजन भी प्रदर्शन में गिरावट का कारण हो सकता है।
एड्रियन शुम

1
@ एड्रियन, मैं यह मान रहा था कि सबसे सामान्य प्रश्न लॉगिन समय पर होंगे और केवल किसी भी हटाए गए उपयोगकर्ता को लॉग इन करने की अनुमति नहीं होगी।
इयान

1
यदि यह एक प्रदर्शन मुद्दा बन जाता है और आप एक एकल तालिका का लाभ चाहते हैं, तो isdeleted पर अनुक्रमित दृश्य का उपयोग करें।
जेएफओ

10

मैं दृढ़ता से उसी तालिका का उपयोग करने की सलाह देता हूं। मुख्य कारण डेटा अखंडता है। सबसे अधिक संभावना है कि उपयोगकर्ताओं के आधार पर रिश्तों के साथ कई तालिकाएं होने जा रही हैं। जब कोई उपयोगकर्ता हटा दिया जाता है तो आप उन रिकॉर्डों को अनाथ नहीं छोड़ना चाहते हैं।
अनाथ रिकॉर्ड होने से, दोनों ही बाधाओं को लागू करना कठिन हो जाता है, और ऐतिहासिक जानकारी को देखना अधिक कठिन हो जाता है। यदि कोई उपयोगकर्ता किसी उपयोग किए गए ईमेल की आपूर्ति करता है तो विचार करने के लिए कि क्या आप उन्हें अपने सभी पुराने रिकॉर्डों को पुनर्प्राप्त करना चाहते हैं। यह सॉफ्ट डिलीट का उपयोग करके अपने आप काम करेगा। जहाँ तक इसे कोड करने की बात है, उदाहरण के लिए मेरे वर्तमान c # linq एप्लिकेशन में जहाँ डिलीट किया गया = 0 क्लॉज स्वचालित रूप से सभी प्रश्नों के अंत में संलग्न है


7

"मैंने जो देखा है वह यह है कि हमारे सिस्टम में, सामान्य चीजों में, हम लगातार पूछते हैं कि उपयोगकर्ता द्वारा जाँच की जाने वाली तालिका उपयोगकर्ता को हटा नहीं रही है"

इससे मुझे डिजाइन की बदबू आती है। आपको इस तरह के तर्क को छिपाना चाहिए। उदाहरण के लिए, आपके पास कुछ UserServiceकरने के isValidUser(userId)बजाय "आपके सिस्टम के पार" उपयोग करने के लिए एक विधि होनी चाहिए :

"उपयोगकर्ता रिकॉर्ड प्राप्त करें, जांचें कि क्या उपयोगकर्ता को हटाए जाने के रूप में चिह्नित किया गया है"।

हटाए गए उपयोगकर्ता को संग्रहीत करने का आपका तरीका व्यावसायिक तर्क को प्रभावित नहीं करना चाहिए।

इस तरह के एनकैप्सुलेशन के साथ, उपरोक्त तर्क को अब आपकी दृढ़ता के दृष्टिकोण को प्रभावित नहीं करना चाहिए। फिर आप स्वयं दृढ़ता से संबंधित पेशेवरों और विपक्षों पर अधिक ध्यान केंद्रित कर सकते हैं।

जिन बातों पर विचार करना है उनमें शामिल हैं:

  • हटाए गए रिकॉर्ड को वास्तव में कब तक शुद्ध किया जाना चाहिए?
  • हटाए गए रिकॉर्ड का अनुपात क्या है?
  • क्या संदर्भात्मक अखंडता के लिए कोई समस्या होगी (उदाहरण के लिए उपयोगकर्ता को अन्य तालिका से संदर्भित किया जाता है) यदि आप वास्तव में इसे तालिका से हटाते हैं?
  • क्या आप उपयोगकर्ता को फिर से खोलने पर विचार कर रहे हैं?

आम तौर पर मैं एक संयुक्त तरीका अपनाऊंगा:

  1. हटाए गए रिकॉर्ड को चिह्नित करें (कार्यात्मक आवश्यकता के लिए रखने के लिए, जैसे एसी को फिर से खोलना, या हाल ही में बंद किए गए एसी की जांच करना)।
  2. पूर्वनिर्धारित अवधि के बाद, हटाए गए रिकॉर्ड को संग्रह तालिका (बहीखाता उद्देश्य के लिए) में स्थानांतरित करें।
  3. कुछ पूर्वनिर्धारित संग्रह अवधि के बाद इसे शुद्ध करें।

1
[Clarification1: 'लगातार क्वेरी' द्वारा, मेरा मतलब है कि हमारे पास ऐसे प्रश्न हैं जो इस तरह हैं: '... उपयोगकर्ताओं से जहां = "0" और ...'। उदाहरण के लिए, हमें किसी विशेष तिथि पर सभी बैठकों के लिए पंजीकृत सभी उपयोगकर्ताओं को लाने की आवश्यकता हो सकती है, इसलिए इस प्रश्न में, हमारे पास उपयोगकर्ताओं से भी है, जहां = "0" - क्या यह मेरी बात को स्पष्ट करता है?] @ एड्रियन
एलन बीट

हाँ बहुत साफ है। :) अगर मैं ऐसा कर रहा हूं, तो मैं इसे भौतिक / तार्किक हटाए जाने के बजाय उपयोगकर्ता की स्थिति में बदलाव के रूप में बताऊंगा। हालांकि कोड की मात्रा कम नहीं होगी ("और iseleted = '0'" vs "और" State <> 'TERMINATED' ") लेकिन सब कुछ बहुत अधिक उचित लगेगा, और अलग-अलग उपयोगकर्ता स्थिति भी होना सामान्य है। आवधिक उपयोगकर्ताओं का आवधिक-शुद्धिकरण भी किया जा सकता है, जैसा कि मेरे पिछले उत्तर में सुझाया गया है)
एड्रियन शुम

5

इस प्रश्न का ठीक से उत्तर देने के लिए आपको सबसे पहले यह तय करने की आवश्यकता है: इस प्रणाली / आवेदन के संदर्भ में "डिलीट" का क्या अर्थ है?

उस प्रश्न का उत्तर देने के लिए, आपको एक और प्रश्न का उत्तर देने की आवश्यकता है: रिकॉर्ड क्यों हटाए जा रहे हैं?

उपयोगकर्ता को डेटा को हटाने की आवश्यकता हो सकती है क्यों कई अच्छे कारण हैं। आमतौर पर मुझे पता चलता है कि वास्तव में एक कारण (प्रति तालिका) है कि क्यों एक हटाना आवश्यक हो सकता है। कुछ उदाहरण निम्न हैं:

  • डिस्क स्थान को पुनः प्राप्त करने के लिए;
  • प्रतिधारण / गोपनीयता नीति के अनुसार हार्ड-विलोपन;
  • दूषित / निराशाजनक रूप से गलत डेटा, मरम्मत करने की तुलना में हटाना और पुन: उत्पन्न करना आसान है।
  • बहुमत पंक्तियों की नष्ट हो जाती हैं, जैसे एक लॉग तालिका एक्स रिकॉर्ड करने के लिए सीमित / दिन।

हार्ड-विलोपन के कुछ बहुत खराब कारण भी हैं (बाद में इन कारणों पर अधिक):

  • एक छोटी सी त्रुटि को ठीक करने के लिए। यह आमतौर पर डेवलपर आलस्य और एक प्रतिकूल यूआई को रेखांकित करता है।
  • एक लेनदेन "शून्य" करने के लिए (उदाहरण के लिए चालान जिसे कभी भी बिल नहीं किया जाना चाहिए)।
  • क्योंकि आप कर सकते हैं

क्यों, आप पूछते हैं, क्या यह वास्तव में इतनी बड़ी बात है? अच्छा OLE के साथ 'गलत क्या है DELETE?

  • किसी भी प्रणाली में पैसे के लिए दूर से बंधा हुआ, हार्ड-विलोपन सभी प्रकार की लेखांकन अपेक्षाओं का उल्लंघन करता है, भले ही संग्रह / कब्र की मेज पर ले जाया गया हो। इसे संभालने का सही तरीका एक पूर्वव्यापी घटना है
  • पुरालेख तालिकाओं में लाइव स्कीमा से अलग होने की प्रवृत्ति है। यदि आप एक नए जोड़े गए कॉलम या कैसकेड के बारे में भूल जाते हैं, तो आप उस डेटा को स्थायी रूप से खो देते हैं।
  • विशेष रूप से कैस्केड के साथ हार्ड विलोपन एक बहुत महंगा ऑपरेशन हो सकता है । लोगों का एक बहुत है कि व्यापक और अधिक से अधिक एक स्तर या कुछ मामलों में एहसास नहीं है ( किसी भी कैस्केडिंग, डीबीएमएस पर निर्भर करता है) के परिणामस्वरूप सेट-ऑपरेशन के बजाय रिकॉर्ड स्तर के ऑपरेशन होंगे।
  • बार-बार, लगातार हार्ड विलोपन सूचकांक विखंडन की प्रक्रिया को गति देता है।

तो, मुलायम हटाना बेहतर है, है ना? नहीं वास्तव में नहीं:

  • कैस्केड सेट करना बेहद मुश्किल हो जाता है। आप लगभग हमेशा ग्राहक को अनाथ पंक्तियों के रूप में दिखाई देते हैं।
  • आपको केवल एक विलोपन ट्रैक करने के लिए मिलता है । क्या होगा यदि पंक्ति को हटा दिया जाए और कई बार हटाया नहीं जाए?
  • प्रदर्शन पीडि़त पढ़ें, हालांकि यह विभाजन, विचारों और / या फ़िल्टर किए गए अनुक्रमित के साथ कुछ हद तक कम किया जा सकता है।
  • जैसा कि पहले संकेत दिया गया था, यह वास्तव में कुछ परिदृश्यों / न्यायालयों में अवैध हो सकता है।

सच्चाई यह है कि ये दोनों दृष्टिकोण गलत हैं। हटाना गलत है। यदि आप वास्तव में यह सवाल पूछ रहे हैं तो इसका मतलब है कि आप लेनदेन के बजाय वर्तमान स्थिति को मॉडलिंग कर रहे हैं। यह डेटाबेस-भूमि में एक बुरा, बुरा अभ्यास है।

Udi Dahan ने इसके बारे में डोंट डिलीट - जस्ट डोन्ट में लिखा । नहीं है हमेशा किसी प्रकार का कार्य, लेन-देन, गतिविधि , या (मेरी पसंदीदा शब्द) घटना जो वास्तव में "हटाएँ" का प्रतिनिधित्व करता है। यदि आप बाद में प्रदर्शन के लिए "वर्तमान स्थिति" तालिका में अपभ्रंश करना चाहते हैं तो यह ठीक है, लेकिन ऐसा करें कि आपके द्वारा लेन-देन मॉडल को नीचे किए जाने के बाद , इससे पहले नहीं।

इस मामले में आपके पास "उपयोगकर्ता" हैं। उपयोगकर्ता अनिवार्य रूप से ग्राहक हैं। ग्राहकों का आपके साथ व्यावसायिक संबंध है। यह संबंध केवल पतली हवा में गायब नहीं होता है क्योंकि उन्होंने अपना खाता रद्द कर दिया है। वास्तव में क्या हो रहा है:

  • ग्राहक खाता बनाता है
  • ग्राहक खाता रद्द करता है
  • ग्राहक खाता नवीनीकृत करता है
  • ग्राहक खाता रद्द करता है
  • ...

हर मामले में, यह एक ही ग्राहक है , और संभवतः एक ही खाता (यानी प्रत्येक खाता नवीनीकरण एक नया सेवा अनुबंध है)। तो आप पंक्तियों को क्यों हटा रहे हैं? यह मॉडल करना बहुत आसान है:

+-----------+       +-------------+       +-----------------+
| Account   | --->* | Agreement   | --->* | AgreementStatus |
+-----------+       +-------------+       +----------------+
| Id        |       | Id          |       | AgreementId     |
| Name      |       | AccountId   |       | EffectiveDate   |
| Email     |       | ...         |       | StatusCode      |
+-----------+       +-------------+       +-----------------+

बस। यही सब है इसके लिए। आपको कभी भी कुछ भी हटाने की आवश्यकता नहीं है। उपरोक्त एक काफी सामान्य डिजाइन है जो लचीलेपन की एक अच्छी डिग्री को समायोजित करता है लेकिन आप इसे थोड़ा सरल कर सकते हैं; आप तय कर सकते हैं कि आपको "अनुबंध" स्तर की आवश्यकता नहीं है और बस "खाता" एक "खाता सूची" तालिका पर जाएं।

यदि आपके आवेदन में लगातार आवश्यकता को सक्रिय समझौतों / खातों की सूची प्राप्त करना है, तो यह एक (थोड़ा) मुश्किल क्वेरी है, लेकिन इसके लिए क्या विचार हैं:

CREATE VIEW ActiveAgreements AS
SELECT agg.Id, agg.AccountId, acc.Name, acc.Email, s.EffectiveDate, ...
FROM AgreementStatus s
INNER JOIN Agreement agg
    ON agg.Id = s.AgreementId
INNER JOIN Account acc
    ON acc.Id = agg.AccountId
WHERE s.StatusCode = 'ACTIVE'
AND NOT EXISTS
(
    SELECT 1
    FROM AgreementStatus so
    WHERE so.AgreementId = s.AgreementId
    AND so.EffectiveDate > s.EffectiveDate
)

और आपने कल लिया। अब आपके पास सॉफ्ट-डिलीट के सभी लाभों के साथ कुछ है लेकिन कमियां नहीं हैं:

  • अनाथ रिकॉर्ड एक गैर-मुद्दा है क्योंकि सभी रिकॉर्ड हर समय दिखाई देते हैं; जब भी आवश्यक हो आप एक अलग दृष्टिकोण से चयन करें।
  • "हटाना" आमतौर पर एक अविश्वसनीय रूप से सस्ता ऑपरेशन है - बस एक पंक्ति को एक घटना तालिका में सम्मिलित करना।
  • किसी भी इतिहास को खोने का कोई मौका नहीं है, कभी भी , चाहे आप कितनी भी बुरी तरह से पंगा लें।
  • यदि आपको जरूरत है (उदाहरण के लिए गोपनीयता कारणों से), तो आप अभी भी किसी खाते को हार्ड-डिलीट कर सकते हैं , और इस ज्ञान के साथ सहज रहें कि डिलीट साफ-सुथरा होगा और ऐप / डेटाबेस के किसी अन्य हिस्से के साथ हस्तक्षेप नहीं करेगा।

केवल समस्या से निपटने के लिए छोड़ा गया मुद्दा प्रदर्शन है। कई मामलों में यह वास्तव में गैर-इश्यू के कारण क्लस्टर इंडेक्स पर बदल जाता है AgreementStatus (AgreementId, EffectiveDate)- वहां पर बहुत कम I / O मांग रहा है। लेकिन अगर यह कभी मुद्दा है, तो इसे हल करने के तरीके हैं, ट्रिगर्स, अनुक्रमित / भौतिक विचारों, एप्लिकेशन-स्तरीय घटनाओं आदि का उपयोग करना।

प्रदर्शन के बारे में बहुत जल्दी चिंता न करें - डिज़ाइन को सही तरीके से प्राप्त करना अधिक महत्वपूर्ण है, और इस मामले में "सही" का अर्थ है डेटाबेस का उपयोग करना जिस तरह से डेटाबेस का उपयोग किया जाना है, एक ट्रांजेक्शनल सिस्टम के रूप में।


1

मैं वर्तमान में एक सिस्टम के साथ काम कर रहा हूं, जहां हर टेबल में सॉफ्ट-डिलीट के लिए डिलीट किया हुआ झंडा है। यह सभी अस्तित्व का प्रतिबंध है। यह पूरी तरह से संबंधपरक अखंडता को तोड़ देता है जब एक उपयोगकर्ता एक तालिका से एक रिकॉर्ड "हटा" सकता है, फिर भी बच्चे रिकॉर्ड करते हैं जो एफके वापस उस तालिका में नरम-हटाए नहीं जाते हैं। समय बीतने के बाद वास्तव में ट्रैश डेटा के लिए बनाता है।

इसलिए, मैं अलग-अलग हिस्ट्री टेबल की सलाह देता हूं।


निश्चित रूप से कैस्केड किए गए इतिहास-बदलाव के बिना, आपके पास बिल्कुल वही समस्या है?
ग्लेनट्रॉन

अपने सक्रिय रिकॉर्ड तालिकाओं में नहीं, नहीं।
जेसी सी। स्लाइसर

तो क्या होता है बच्चे के रिकॉर्ड के बाद, जो उपयोगकर्ता तालिका से FK को हटा दिया जाता है, जब उपयोगकर्ता को इतिहास तालिका में भेज दिया जाता है?
ग्लेनट्रॉन

आपका ट्रिगर (या व्यावसायिक तर्क) बच्चे के रिकॉर्ड को उनके संबंधित इतिहास तालिकाओं के साथ भी संरेखित करेगा। मुद्दा यह है कि आप डेटाबेस को बताए बिना मूल रिकॉर्ड (इतिहास में जाने के लिए) को भौतिक रूप से हटा नहीं सकते हैं, ताकि आप आरआई को तोड़ सकें। तो आप इसे डिजाइन करने के लिए मजबूर हैं। हटाए गए ध्वज में कैस्केडिंग नरम-हटाए जाने को बाध्य नहीं करता है।
जेसी सी। स्लाइसर

3
निर्भर करता है कि वास्तव में आपके सॉफ्ट डिलीट का क्या मतलब है। यदि यह उन्हें निष्क्रिय करने का एक तरीका है, तो एक निष्क्रिय खाते से संबंधित रिकॉर्ड को समायोजित करने की कोई आवश्यकता नहीं है। मेरे लिए सिर्फ डेटा की तरह लगता है। और हाँ, मुझे इसके साथ एक प्रणाली से निपटना होगा जिसे मैंने डिज़ाइन नहीं किया था। इसका मतलब यह नहीं है कि आपको इसे पसंद करना है।
जेफो जूल 20'11

1

दो में तालिका को तोड़ने के लिए सबसे मुश्किल चीज होगी।

यहाँ दो बहुत ही सरल कदम हैं, जो मैं सुझाऊंगा:

  1. 'उपयोगकर्ताओं' तालिका का नाम बदलकर 'allusers' रखें।
  2. 'यूजर्स' नामक एक व्यू को ऑल्यूजर्स से 'सेलेक्ट * करें जहाँ डिलीट किया गया है = गलत'।

PS उत्तर देने में कई महीने की देरी के लिए क्षमा करें!


0

यदि आप हटाए गए खातों को पुनर्प्राप्त कर रहे हैं जब कोई उसी ई-मेल पते के साथ वापस आता है तो मैं सभी उपयोगकर्ताओं को एक ही तालिका में रखने के साथ चला गया होता। यह खाता पुनर्प्राप्ति प्रक्रिया को तुच्छ बना देगा।

हालाँकि, जब आप नए खाते बनाते हैं, तो हटाए गए खातों को एक अलग तालिका में ले जाना सरल होगा। लाइव सिस्टम को इस जानकारी की आवश्यकता नहीं है, इसलिए इसे उजागर न करें। जैसा कि आप कहते हैं कि यह प्रश्नों को सरल बनाता है और संभवत: बड़े डेटासेट पर अधिक तेज होता है। सरल कोड भी बनाए रखना आसान है।


0

आप उपयोग में DBMS का उल्लेख नहीं करते हैं। यदि आपके पास उचित लाइसेंस के साथ ओरेकल है, तो आप उपयोगकर्ताओं की तालिका को दो भागों में विभाजित करने पर विचार कर सकते हैं: सक्रिय और हटाए गए उपयोगकर्ता।


फिर आपको उपयोगकर्ताओं को हटाते समय एक विभाजन से दूसरे में पंक्तियों को स्थानांतरित करना होगा, जो निश्चित रूप से नहीं है कि विभाजन का उपयोग करने का इरादा कैसे है।
पेटर तोलुक

@ पैटर: हुह? आप हटाए गए ध्वज सहित किसी भी मापदंड पर विभाजन कर सकते हैं।
हारून ने

@Aaronaught, OK, मैंने इसे गलत बताया। DBMS आपके लिए काम कर सकता है, लेकिन यह अभी भी अतिरिक्त काम है (क्योंकि पंक्ति को भौतिक रूप से एक स्थान से दूसरे स्थान पर ले जाना चाहिए, संभवतः एक अलग फ़ाइल में), और यह डेटा के भौतिक वितरण को खराब कर सकता है।
पेटर तोर्क
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.