Bcp / BULK INSERT बनाम टेबल-वेल्यूड पैरामीटर्स का प्रदर्शन


84

मैं SQL सर्वर BULK INSERTकमांड का उपयोग करते हुए कुछ पुराने कोड को फिर से लिखना चाहता हूं क्योंकि स्कीमा बदल गया है, और यह मेरे लिए हुआ है कि शायद मुझे इसके बजाय एक टीवीपी के साथ संग्रहीत प्रक्रिया पर स्विच करने के बारे में सोचना चाहिए, लेकिन मैं सोच रहा हूं कि क्या प्रभाव है यह प्रदर्शन पर हो सकता है।

कुछ पृष्ठभूमि की जानकारी जो यह बताने में मदद कर सकती है कि मैं यह प्रश्न क्यों पूछ रहा हूं:

  • डेटा वास्तव में एक वेब सेवा के माध्यम से आता है। वेब सेवा डेटाबेस सर्वर पर एक साझा फ़ोल्डर में एक पाठ फ़ाइल लिखती है जो बदले में एक कार्य करती है BULK INSERT। यह प्रक्रिया मूल रूप से SQL Server 2000 पर लागू की गई थी, और उस समय INSERTसर्वर पर कुछ सौ बयानों को चकित करने के अलावा वास्तव में कोई विकल्प नहीं था , जो वास्तव में मूल प्रक्रिया थी और एक प्रदर्शन आपदा थी।

  • डेटा को एक स्थायी मंचन तालिका में डाला जाता है और फिर एक बहुत बड़ी तालिका में विलय कर दिया जाता है (जिसके बाद इसे मंचन तालिका से हटा दिया जाता है)।

  • सम्मिलित करने के लिए डेटा की मात्रा "बड़ी" है, लेकिन "विशाल" नहीं है - आमतौर पर कुछ सौ पंक्तियां, शायद दुर्लभ साधनों में 5-10k पंक्तियां सबसे ऊपर हैं। इसलिए मेरी आंत की भावना यह है कि BULK INSERTएक गैर-लॉग ऑपरेशन होने से वह बड़ा नहीं होगा (लेकिन निश्चित रूप से मुझे यकीन नहीं है, इसलिए सवाल)।

  • सम्मिलन वास्तव में एक बहुत बड़ी पाइपलाइन प्रक्रिया का हिस्सा है और उत्तराधिकार में कई बार होने की आवश्यकता होती है; इसलिए प्रदर्शन है महत्वपूर्ण।

जिन कारणों को मैं BULK INSERTटीवीपी के साथ बदलना चाहूंगा वे हैं:

  • NetBIOS पर टेक्स्ट फ़ाइल लिखना संभवतः पहले से ही कुछ समय का खर्च है, और यह एक वास्तुशिल्प दृष्टिकोण से बहुत भीषण है।

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

  • मैं बहुत अधिक डुप-चेकिंग, क्लीनअप कोड और थोक आवेषण के साथ जुड़े ओवरहेड के साथ बहुत कुछ कर सकता था।

  • स्टेजिंग टेबल या टेम्पर्डब पर लॉक कंटेस्टेंट के बारे में चिंता करने की कोई ज़रूरत नहीं है अगर सर्वर को एक ही बार में इनमें से कुछ ट्रांजैक्शन मिलते हैं (हम इसे टालने की कोशिश करते हैं, लेकिन ऐसा होता है)।

मैं स्पष्ट रूप से उत्पादन में कुछ भी डालने से पहले इसे प्रोफाइल करने जा रहा हूं, लेकिन मैंने सोचा कि यह एक अच्छा विचार हो सकता है कि इससे पहले कि मैं वह सारा समय बिताऊं, इससे पहले कि कोई भी इस उद्देश्य के लिए टीवीपी का उपयोग करने के बारे में कोई सख्त चेतावनी दे।

तो - किसी के लिए जो SQL Server 2008 के साथ पर्याप्त आरामदायक है या कम से कम इसकी जांच करने की कोशिश की है, क्या फैसला है? आवेषण के लिए, मान लें कि कुछ सौ से कुछ हज़ार पंक्तियों में, काफी हद तक लगातार हो रहा है, क्या टीवीपी सरसों को काटते हैं? क्या थोक आवेषण की तुलना में प्रदर्शन में महत्वपूर्ण अंतर है?


अद्यतन: अब 92% कम प्रश्नवाचक चिन्ह के साथ!

(AKA: परीक्षा परिणाम)

36-चरण परिनियोजन प्रक्रिया की तरह महसूस करने के बाद अंतिम परिणाम अब उत्पादन में है। दोनों समाधानों का बड़े पैमाने पर परीक्षण किया गया:

  • साझा-फ़ोल्डर कोड को रिप करना और SqlBulkCopyसीधे वर्ग का उपयोग करना ;
  • TVPs के साथ एक संग्रहीत कार्यविधि पर स्विच करना।

बस इसलिए पाठकों को इस बात का अंदाजा हो सकता है कि वास्तव में क्या परीक्षण किया गया था, इस डेटा की विश्वसनीयता के रूप में किसी भी संदेह को दूर करने के लिए, यहां यह अधिक विस्तृत विवरण है कि यह आयात प्रक्रिया वास्तव में क्या करती है :

  1. एक अस्थायी डेटा अनुक्रम के साथ शुरू करें जो सामान्य रूप से लगभग 20-50 डेटा बिंदु हैं (हालांकि यह कभी-कभी कुछ सौ तक हो सकता है);

  2. उस पर पागल प्रसंस्करण का एक पूरा गुच्छा करो जो ज्यादातर डेटाबेस से स्वतंत्र है। इस प्रक्रिया को समानांतर किया जाता है, इसलिए एक ही समय में (1) में से लगभग 8-10 अनुक्रमों को संसाधित किया जा रहा है। प्रत्येक समानांतर प्रक्रिया 3 अतिरिक्त अनुक्रम उत्पन्न करती है।

  3. सभी 3 अनुक्रम और मूल अनुक्रम लें और उन्हें एक बैच में संयोजित करें।

  4. एक बड़े सुपर-बैच में सभी 8-10 अब समाप्त प्रसंस्करण कार्यों से बैचों को मिलाएं।

  5. इसे या तो BULK INSERTरणनीति (अगला चरण देखें), या टीवीपी रणनीति (चरण 8 पर छोड़ें) का उपयोग करके आयात करें ।

  6. SqlBulkCopyपूरे सुपर-बैच को 4 स्थायी मेज़िंग टेबल में डंप करने के लिए कक्षा का उपयोग करें ।

  7. एक संग्रहीत प्रक्रिया चलाएं कि (ए) तालिका के 2 पर एकत्रीकरण चरणों का एक गुच्छा करता है, जिसमें कई JOINस्थितियां शामिल हैं, और फिर (बी) MERGEकुल और गैर-एकत्रित डेटा दोनों का उपयोग करके 6 उत्पादन तालिकाओं पर प्रदर्शन करता है । (ख़त्म होना)

    या

  8. DataTableमर्ज किए जाने वाले डेटा वाले 4 ऑब्जेक्ट उत्पन्न करें ; उनमें से 3 में CLR प्रकार होते हैं जो दुर्भाग्य से ADO.NET TVPs द्वारा ठीक से समर्थित नहीं होते हैं, इसलिए उन्हें स्ट्रिंग अभ्यावेदन के रूप में जाना जाता है, जो प्रदर्शन को थोड़ा नुकसान पहुंचाता है।

  9. टीवीएस को एक संग्रहीत प्रक्रिया में फ़ीड करें, जो अनिवार्य रूप से (7) के रूप में एक ही प्रसंस्करण करता है, लेकिन सीधे प्राप्त तालिकाओं के साथ। (ख़त्म होना)

परिणाम काफी करीब थे, लेकिन टीवीपी के दृष्टिकोण ने अंततः औसत पर बेहतर प्रदर्शन किया, तब भी जब डेटा एक छोटी राशि से 1000 पंक्तियों से अधिक था।

ध्यान दें कि यह आयात प्रक्रिया उत्तराधिकार में कई बार हजारों बार चलाई जाती है, इसलिए औसत समय प्राप्त करना बहुत आसान था, गिनती के कितने घंटे (हाँ, घंटे) यह सभी मर्जों को पूरा करने के लिए ले लिया।

मूल रूप से, एक औसत मर्ज को पूरा होने में लगभग 8 सेकंड लगते थे (सामान्य भार के तहत)। NetBIOS कीचड़ को हटाकर SqlBulkCopyसमय को घटाकर लगभग 7 सेकंड कर दिया गया। TVPs पर स्विच करने से समय प्रति बैच 5.2 सेकंड कम हो गया । यह एक प्रक्रिया के लिए थ्रूपुट में 35% सुधार है जिसका चल रहा समय घंटों में मापा जाता है - इसलिए बुरा बिल्कुल नहीं। यह भी ~ 25% से अधिक सुधार है SqlBulkCopy

मैं वास्तव में काफी आश्वस्त हूं कि सही सुधार इससे काफी अधिक था। परीक्षण के दौरान यह स्पष्ट हो गया कि अंतिम विलय अब महत्वपूर्ण मार्ग नहीं था; इसके बजाय, वेब सेवा जो सभी डेटा प्रोसेसिंग कर रही थी, आने वाले अनुरोधों की संख्या के तहत बकसुआ बनाना शुरू कर रही थी। न तो सीपीयू और न ही डेटाबेस I / O वास्तव में अधिकतम थे, और कोई महत्वपूर्ण लॉकिंग गतिविधि नहीं थी। कुछ मामलों में हम क्रमिक विलय के बीच कुछ निष्क्रिय सेकंड का अंतर देख रहे थे। उपयोग करते समय थोड़ा अंतर था, लेकिन बहुत छोटा (आधा सेकंड या ऐसा ही) SqlBulkCopy। लेकिन मुझे लगता है कि एक और दिन के लिए एक कहानी बन जाएगी।

निष्कर्ष: टेबल-वैल्यूड पैरामीटर्स वास्तव में BULK INSERTमध्य आकार के डेटा सेट पर संचालित होने वाले जटिल आयात + परिवर्तन प्रक्रियाओं के संचालन से बेहतर प्रदर्शन करते हैं ।


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

दूसरे शब्दों में, हमारे पास पहले से ही प्रक्रिया में पर्याप्त अंतर्दृष्टि है और एक मंचन की सुरक्षा की आवश्यकता नहीं है; एकमात्र कारण यह था कि पहले चरण में हमारे पास मंच था और उन सभी INSERTऔर UPDATEकथनों पर जोर देने से बचने के लिए जिन्हें हमें अन्यथा उपयोग करना होगा। मूल प्रक्रिया में, स्टेजिंग डेटा केवल एक दूसरे के अंशों के लिए स्टेजिंग टेबल में रहता था, इसलिए इसने रखरखाव / रखरखाव की शर्तों में कोई मूल्य नहीं जोड़ा।

यह भी ध्यान दें कि हमने हर एक ऑपरेशन को टीवीपी से बदला नहीं हैBULK INSERT । कई ऑपरेशन जो बड़ी मात्रा में डेटा के साथ काम करते हैं और / या इसे अभी भी उपयोग किए जाने वाले डीबी पर फेंकने के अलावा डेटा के साथ कुछ विशेष करने की आवश्यकता नहीं है SqlBulkCopyमैं यह नहीं सुझाव दे रहा हूं कि टीवीपी एक प्रदर्शन रामबाण है, केवल यह कि वे SqlBulkCopyइस विशिष्ट उदाहरण में सफल रहे जिसमें प्रारंभिक मंचन और अंतिम मर्ज के बीच कई परिवर्तन शामिल थे।

इसलिए यह अब आपके पास है। सबसे प्रासंगिक लिंक खोजने के लिए प्वाइंट टीटीओनी जाता है, लेकिन मैं अन्य प्रतिक्रियाओं की भी सराहना करता हूं। एक बार फिर धन्यवाद!


यह अपने आप में एक अद्भुत सवाल है, मुझे लगता है कि अपडेट का हिस्सा एक उत्तर में होना चाहिए;)
मार्क .२ amazing7

जवाबों:


10

मेरे पास अभी तक टीवीपी के साथ अनुभव नहीं है, हालांकि यहाँ MSDN में BULK INSERT बनाम एक अच्छा प्रदर्शन तुलना चार्ट है

उनका कहना है कि BULK INSERT की स्टार्टअप लागत अधिक है, लेकिन उसके बाद तेजी से आगे बढ़ रही है। दूरस्थ क्लाइंट परिदृश्य में वे लगभग 1000 पंक्तियों ("सरल" सर्वर लॉजिक के लिए) रेखा खींचते हैं। उनके विवरण को देखते हुए मैं कहूंगा कि आपको टीवीपी के इस्तेमाल से ठीक होना चाहिए। प्रदर्शन हिट - यदि कोई हो - शायद नगण्य है और वास्तु लाभ बहुत अच्छा लगता है।

संपादित करें: साइड नोट पर आप सर्वर-स्थानीय फ़ाइल से बच सकते हैं और फिर भी SqlBulkCopy ऑब्जेक्ट का उपयोग करके बल्क कॉपी का उपयोग कर सकते हैं। बस एक DataTable को पॉप्युलेट करें, और इसे SqlBulkCopy उदाहरण के "WriteToServer" -Method में फीड करें। प्रयोग करने में आसान, और बहुत तेज।


लिंक के लिए धन्यवाद, यह वास्तव में काफी उपयोगी है क्योंकि एमएस को टीवीपी की सिफारिश करने के लिए लगता है जब डेटा जटिल तर्क खिलाता है (जो यह करता है) और हमारे पास बैच आकार को डायल या डाउन करने की क्षमता भी है, इसलिए हम बहुत दूर नहीं जाते हैं 1k-row दर्द बिंदु। इसके आधार पर, यह कम से कम कोशिश करने और देखने का समय हो सकता है, भले ही यह बहुत धीमा हो।
आरोहण २

हाँ लिंक दिलचस्प है। @ चेतावनी - इस तरह की स्थितियों में, संभावित दृष्टिकोणों के प्रदर्शन की खोज और विश्लेषण करना हमेशा अच्छा होता है, इसलिए मुझे आपके निष्कर्षों को सुनने में दिलचस्पी होगी!
अादिदेव

7

@ टीटोनी के उत्तर में दिए गए लिंक के संबंध में उल्लेखित चार्ट को संदर्भ में लेने की आवश्यकता है। मुझे यकीन नहीं है कि उन सिफारिशों में कितना वास्तविक शोध हुआ (यह भी ध्यान दें कि चार्ट केवल उस दस्तावेज़ के संस्करणों 2008और 2008 R2संस्करणों में उपलब्ध है )।

दूसरी ओर एसक्यूएल सर्वर ग्राहक सलाहकार टीम से यह व्हाइटपेपर है: टीवीपी के साथ मैक्सिमाइज़िंग थ्रूपुट

मैं 2009 से टीवीपी का उपयोग कर रहा हूं और मैंने पाया है, कम से कम मेरे अनुभव में, कि किसी भी अतिरिक्त तर्क आवश्यकताओं (जो शायद ही कभी मामला है) के साथ एक गंतव्य तालिका में सरल सम्मिलित करने के अलावा, तो टीवीपी आमतौर पर बेहतर विकल्प हैं।

मैं मंचन से बचना चाहता हूं क्योंकि डेटा सत्यापन को ऐप परत पर किया जाना चाहिए। TVPs का उपयोग करके, जिसे आसानी से समायोजित किया जाता है और संग्रहीत कार्यविधि में TVP तालिका परिवर्तनीय है, इसकी प्रकृति से, एक स्थानीयकृत मेज़िंग तालिका (इसलिए उसी समय चल रही अन्य प्रक्रियाओं के साथ कोई संघर्ष नहीं होता है जब आप मंचन के लिए एक वास्तविक तालिका का उपयोग करते समय प्राप्त करते हैं। )।

प्रश्न में किए गए परीक्षण के बारे में, मुझे लगता है कि मूल रूप से जो पाया गया था, उससे कहीं अधिक तेजी से दिखाया जा सकता है:

  1. जब तक आपके एप्लिकेशन ने इसका उपयोग टीवीपी के मूल्यों को भेजने के बाहर नहीं किया, तब तक आपको डेटाटेबल का उपयोग नहीं करना चाहिए। का उपयोग करते हुए IEnumerable<SqlDataRecord>इंटरफ़ेस तेजी से होता है और आप स्मृति में संग्रह की प्रतिलिपि नहीं कर रहे हैं के रूप में केवल DB को भेजने के लिए कम स्मृति का उपयोग करता है। मैंने निम्नलिखित स्थानों में यह प्रलेखित किया है:
  2. टीवीपी टेबल वेरिएबल्स हैं और इस तरह से आंकड़े नहीं बनाए जाते हैं। मतलब, वे क्वेरी ऑप्टिमाइज़र के लिए केवल 1 पंक्ति होने की रिपोर्ट करते हैं। तो, आपकी खरीद में, या तो:
    • एक सरल चयन के अलावा टीवीपी का उपयोग करके किसी भी प्रश्न पर स्टेटमेंट-स्तर की पुनर्संरचना का उपयोग करें: OPTION (RECOMPILE)
    • एक स्थानीय अस्थायी तालिका (यानी एकल #) बनाएं और टीवीपी की सामग्री को अस्थायी तालिका में कॉपी करें

4

मुझे लगता है कि मैं अभी भी एक थोक सम्मिलित दृष्टिकोण के साथ रहना चाहूंगा। आप पा सकते हैं कि टेम्पर्डब अभी भी उचित संख्या में पंक्तियों के साथ टीवीपी का उपयोग करके हिट हो जाता है। यह मेरी आंत की भावना है, मैं यह नहीं कह सकता कि मैंने टीवीपी के उपयोग के प्रदर्शन का परीक्षण किया है (मैं दूसरों के इनपुट सुनने में दिलचस्पी रखता हूं, हालांकि)

यदि आप .NET का उपयोग करते हैं तो आप इसका उल्लेख नहीं करते हैं, लेकिन पिछले समाधानों को अनुकूलित करने के लिए मैंने जो दृष्टिकोण लिया है वह SqlBulkCopy वर्ग का उपयोग करके डेटा का एक बड़ा भार उठाने के लिए था - आपको पहले किसी फ़ाइल में डेटा लिखने की आवश्यकता नहीं है लोड हो रहा है, बस SqlBulkCopy वर्ग (जैसे) एक DataTable दे - यह DB में डेटा डालने का सबसे तेज़ तरीका है। 5-10K पंक्तियाँ ज्यादा नहीं हैं, मैंने इसे 750K पंक्तियों के लिए उपयोग किया है। मुझे संदेह है कि सामान्य तौर पर, कुछ सौ पंक्तियों के साथ यह टीवीपी का उपयोग करके एक बड़ा अंतर नहीं लाएगा। लेकिन स्केलिंग सीमित IMHO होगी।

शायद SQL 2008 में नई MERGE कार्यक्षमता आपको लाभान्वित करेगी?

इसके अलावा, यदि आपकी मौजूदा स्टेजिंग टेबल एक सिंगल टेबल है, जिसका उपयोग इस प्रक्रिया के प्रत्येक उदाहरण के लिए किया जाता है और आप विवाद आदि से चिंतित हैं, तो क्या आपने हर बार एक नया "अस्थायी" लेकिन भौतिक मंचन तालिका बनाने पर विचार किया है, तब इसे छोड़ने पर के साथ ख़त्म करना?

ध्यान दें कि आप किसी भी अनुक्रमणिका के बिना इसे लोड करके, इस मंचन तालिका में लोडिंग को अनुकूलित कर सकते हैं। फिर एक बार पॉप्युलेट होने पर, उस बिंदु पर किसी भी आवश्यक इंडेक्स को जोड़ें (इष्टतम पढ़ने के प्रदर्शन के लिए FILLFACTOR = 100, क्योंकि इस बिंदु पर इसे अपडेट नहीं किया जाएगा)।


मैं .NET का उपयोग करता हूं, और यह प्रक्रिया पूर्ववर्ती होती है SqlBulkCopyऔर इसे कभी नहीं बदला गया है। मुझे उस बारे में याद दिलाने के लिए धन्यवाद, यह फिर से देखने लायक हो सकता है। MERGEपहले से ही बड़े पैमाने पर उपयोग किया जाता है, और अस्थायी तालिकाओं को एक बार पहले भी आजमाया गया था, लेकिन इसे धीमा और अधिक कठिन पाया गया था। इनपुट के लिए धन्यवाद!
Aaronaught

-2

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

आगे एक कामकाजी प्रक्रिया के लिए एक छोटा स्कीमा परिवर्तन तय करना प्रक्रिया को नया स्वरूप देने की तुलना में आसान और कम समय लगता है। यदि यह काम कर रहा है और कोई भी इसे बदलने के लिए घंटों तक भुगतान करने को तैयार नहीं है, तो स्कीमा परिवर्तन के कारण तय की जाने वाली जरूरतों को ही ठीक करें। पूरी प्रक्रिया को बदलकर, आप किसी मौजूदा, परीक्षण की गई कार्यविधि में एक छोटा सा बदलाव करके अधिक संभावित नए बग का परिचय देते हैं।

और कैसे आप सभी डेटा सफाई कार्यों के साथ दूर करने जा रहे हैं? आप उन्हें अलग तरीके से कर रहे होंगे, लेकिन उन्हें अभी भी करने की आवश्यकता है। दोबारा, इस प्रक्रिया को बदलने का तरीका आपके द्वारा वर्णित किया जाना बहुत जोखिम भरा है।

व्यक्तिगत रूप से यह मुझे लगता है कि आप नए खिलौनों के साथ खेलने का मौका पाने के बजाय पुरानी तकनीकों का उपयोग करके सिर्फ नाराज हैं। आपको लगता है कि थोक प्रविष्टि के अलावा कोई अन्य परिवर्तन करने की इच्छा के लिए कोई वास्तविक आधार नहीं है, इसलिए 2000 है।


27
SQL 2008 लगभग 2 साल के लिए रहा है और यह प्रक्रिया उम्र भर के लिए रही है, और यह पहली बार है जब मैंने इसे बदलने पर भी विचार किया है। क्या वास्तव में अंत में चुटीली टिप्पणी आवश्यक थी?
Aaronaught
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.