2009-06-05 21 views
25

मूल रूप से कई क्लासिक के लिए क्लासिक कई हैं। उपयोगकर्ताओं और पुरस्कारों के बीच एक उपयोगकर्ता, एक पुरस्कार, और "कई से कई" टेबल मैपिंग।बिगटेबल धीमा है या मैं गूंगा हूँ?

प्रत्येक उपयोगकर्ता के पास 400 पुरस्कारों के क्रम में है और प्रत्येक पुरस्कार लगभग 1/2 उपयोगकर्ताओं को दिया जाता है।

मैं सभी उपयोगकर्ता के पुरस्कारों पर पुन: प्रयास करना चाहता हूं और उनके अंक जोड़ना चाहता हूं। एसक्यूएल में यह एक टेबल कई से अधिक लोगों के बीच जुड़ जाएगा और फिर प्रत्येक पंक्ति के माध्यम से चलना होगा। एक MySQL उदाहरण के साथ एक सभ्य मशीन पर, 400 पंक्तियों का एक बड़ा सौदा नहीं होना चाहिए।

ऐप इंजन पर मैं योग करने के लिए लगभग 10 सेकंड देख रहा हूं। अधिकांश समय Google के डेटास्टोर में खर्च किया जा रहा है। यहाँ cProfile की शुरुआती कुछ पंक्तियाँ है

 
    ncalls tottime percall cumtime percall filename:lineno(function) 
     462 6.291 0.014 6.868 0.015 {google3.apphosting.runtime._apphosting_runtime___python__apiproxy.Wait} 
     913 0.148 0.000 1.437 0.002 datastore.py:524(_FromPb) 
    8212 0.130 0.000 0.502 0.000 datastore_types.py:1345(FromPropertyPb) 
     462 0.120 0.000 0.458 0.001 {google3.net.proto._net_proto___parse__python.MergeFromString} 

अपने डेटा मॉडल गलत है? क्या मैं लुकअप गलत कर रहा हूं? क्या यह एक कमी है कि मुझे कैशिंग और बल्कअपडेटिंग (जो गधे में शाही दर्द होगा) से निपटना होगा।

+9

+1 एलओएल। मुझे इस सवाल का खिताब पसंद है! – Elijah

+1

क्या Google की बिगटेबल मूल रूप से हैश तालिका नहीं है? – balpha

+0

प्रतीक्षा के रूप में वह शीर्ष कार्य ... आप प्रतीक्षा में 6 सेकंड क्यों खर्च कर रहे हैं? – workmad3

उत्तर

20

दोनों ;-)

का एक सा हो सकता है, प्रत्येक परिणाम के लिए एक मानचित्रण मेज पर एक प्रश्न के लिए लौट आए, तो मुझे लगता है कि दर्दनाक होने की अपेक्षा करेंगे । प्रश्नों पर 1000-परिणाम सीमा है क्योंकि बिगटेबल सोचता है कि 1000 परिणाम लौटने पर उचित समय में काम करने की क्षमता की सीमा है। आर्किटेक्चर के आधार पर, मैं 400 प्रश्नों (400 लॉग एन बनाम (लॉग एम) + 400) लौटने वाली एक क्वेरी की तुलना में 400 प्रश्नों को धीमा होने की उम्मीद करता हूं।

अच्छी खबर यह है कि GAE पर, सभी पुरस्कार और उनके अंक मूल्यों वाली एकल hashtable memcaching बिल्कुल स्पष्ट है है (अच्छी तरह से, बिल्कुल स्पष्ट देखा जब मैं एक समय पहले मेम्कैश डॉक्स पर एक नज़र डाली। मुझे नहीं है इसे अभी करने की जरूरत है)।

इसके अलावा, अगर आपको पहले से ही पता नहीं था, for result in query.fetch(1000)for result in query से तेज़ तरीका है, और आप 1000 परिणामों तक किसी भी तरह से प्रतिबंधित हैं। उत्तरार्द्ध के फायदे हैं (1) यदि आप जल्दी से जमानत करते हैं तो यह तेज़ हो सकता है, और (2) यदि Google कभी 1000 से अधिक सीमा बढ़ाता है, तो कोड कोड के बिना लाभ प्राप्त होता है।

जब आप उपयोगकर्ता (या एक पुरस्कार) हटाते हैं तो आपको भी समस्या हो सकती है। मैंने एक परीक्षण में पाया कि मैं समय सीमा के अंदर 300 वस्तुओं को हटा सकता हूं। वे वस्तुएं आपके मैपिंग ऑब्जेक्ट्स की तुलना में अधिक जटिल थीं, जिसमें 3 गुण और 5 सूचकांक (अंतर्निहित सहित) थे, जबकि आपकी मैपिंग तालिका में केवल 2 गुण और 2 (निहित) सूचकांक होते हैं। [संपादित करें: बस एहसास हुआ कि मैंने यह परीक्षण किया था इससे पहले कि मुझे पता था कि db.delete() एक सूची ले सकता है, जो शायद बहुत तेज़ है]।

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

एक और बात: यदि आप एक ही http अनुरोध पर 400 डेटास्टोर क्वेरी कर रहे हैं, तो आप पाएंगे कि आपने अपना अनुरोध तय कोटा मारा है इससे पहले कि आप अपने डेटास्टोर फिक्स्ड कोटा को अच्छी तरह से दबाएं।बेशक अगर आप कोटा के भीतर अच्छी तरह से हैं, या यदि आप पहले कुछ और मार रहे हैं, तो यह आपके ऐप के लिए अप्रासंगिक हो सकता है। लेकिन दो कोटा के बीच का अनुपात 8: 1 जैसा कुछ है, और मैं इसे एक संकेत के रूप में लेता हूं जो Google मेरे डेटा मॉडल की तरह दिखने की अपेक्षा करता है।

+4

महान सलाह। ऐसा लगता है जैसे मुझे सामान्य django मॉडल में जाना चाहिए और इसे सभी को MySQL पर संग्रहीत करना चाहिए जब तक कि मैं स्केलिंग समस्या नहीं डालता। –

+2

यदि आपका डेटा बिगटेबल की तुलना में MySQL में बेहतर है, तो मुझे लगता है कि आपको खुद से पूछना है कि आप ऐप इंजन का उपयोग क्यों कर रहे हैं। यदि कोई अच्छा कारण है (उदाहरण के लिए, "मुफ्त होस्टिंग"), तो मुझे हां लगता है, लेकिन मेरे लिए यह एक हैक की तरह दिखता है। बिगटेबल (और Google के क्लाउड में सामान्य वितरण में) शायद जीएई और किसी भी पुराने लैंप स्टैक के बीच एकमात्र दिलचस्प तकनीकी अंतर है। –

+4

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

0

Google BigTable Google वितरित फ़ाइल सिस्टम पर चलाया जाता है।

डेटा वितरित किया जाता है। हो सकता है कि 400 पंक्तियां mysql अभी भी बेहतर हों, लेकिन बड़े डेटा के लिए Google BigTable तेज हो सकता है।

मुझे लगता है कि वे हमें तेजी से बनाने के लिए memcache का उपयोग करने के लिए प्रोत्साहित करते हैं। आप पुरस्कार मेज पर 400 प्रश्नों कर रहे हैं

19

क्या मेरा डेटा मॉडल गलत है? क्या मैं गलत कर रहा हूं?

हाँ और हाँ, मुझे डर है।

जहां तक ​​आपका डेटा मॉडल चला जाता है, इसे संभालने के लिए अब तक का सबसे अच्छा तरीका उपयोगकर्ता रिकॉर्ड के खिलाफ राशि को संग्रहीत करना है, और जब उपयोगकर्ता किसी पुरस्कार को प्राप्त/खो देता है तो इसे अपडेट करें। वास्तव में समय के विशाल बहुमत के समय, उनके स्कोर को गिनने में कोई बात नहीं है, यह अपरिवर्तित होगा। यदि आप "UserAward" इकाई को "उपयोगकर्ता" की एक बाल इकाई टाइप करते हैं, तो आप स्कोर को अपडेट कर सकते हैं और एक ही परमाणु लेनदेन में UserAward एंट्री डालें या हटा सकते हैं, यह सुनिश्चित करना कि आपकी गिनती हमेशा सटीक है।

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

लुकअप के लिए, ध्यान रखें कि डेटास्टोर संचालन करने की पर्याप्त लागत राउंड-ट्रिप टाइम है। एक get() ऑपरेशन, जो आईडी द्वारा 1 या अधिक रिकॉर्ड देखता है (आप बैच कर सकते हैं!) में लगभग 20-40ms लगते हैं। हालांकि, एक प्रश्न में 160-200 एमएमएस लगते हैं। इसलिए, denormalization की शक्ति।

+0

धन्यवाद। मैंने इस समस्या के लिए मेरी समस्या को थोड़ा सा सरल बना दिया। मैं थोड़ा सा पुरस्कार, साथ ही पुरस्कार विजेताओं को अद्यतन करता हूं। और "UserAwards" को वापस करने के लिए मुझे केवल अंक की तुलना में अधिक जानकारी की आवश्यकता होगी। मुझे पुरस्कार के लिए आइकन और शायद शीर्षक चाहिए। क्या आपका बैच संदर्भों पर किया गया है? जब मेरे पास 400 उपयोगकर्ताअवर्ड पंक्तियां होंगी और मैं उपयोगकर्ता को प्राप्त करने के लिए पैदल चलना शुरू कर दूंगा। यह आईडी द्वारा प्राप्त होगा और उन्हें बैच करेगा? वह वहां lifesaver हो सकता है। –

+0

संदर्भ प्रॉपर्टी रिज़ॉल्यूशन को 'प्राकृतिक' तरीके से बैच करना संभव नहीं है। आप क्या कर सकते हैं myent.properties() ['propname'] को कॉल करें। Get_value_for_datastore (myent) कुंजी को पुनर्प्राप्त करने के लिए, जो आपको चीजों को बैच करने की अनुमति देता है। भले ही आप पुरस्कारों को बहुत अद्यतन करते हैं, फिर भी मैं कैश को अमान्य करने के किसी भी तरीके से स्थानीय स्मृति में या memcache में उन्हें संग्रहीत करने का सुझाव दूंगा। आपका अन्य विकल्प प्रत्येक इकाई पर एक सूचीप्रॉपर्टी (संदर्भ) पुरस्कारों का उपयोग करना है। यदि आपको अपने पुरस्कारों से उपयोगकर्ताओं को देखने की आवश्यकता नहीं है, तो आप ओवरहेड को कम करने के लिए अनुक्रमित = गलत भी सेट कर सकते हैं। –

1

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

यह विचार अच्छी तरह से यहाँ दर्शाया गया है: Building Scalable Complex Apps

0

यहां तक ​​कि आप बिगटेबल का उल्लेख है, मुझे लगता है कि आप क्लाउड एसक्यूएल पर एक संबंधपरक डेटाबेस को लागू कर रहे हैं।

आपका मॉडल ठीक है, यह ऐसा कुछ करने का उचित तरीका है। मुझे उपयोगकर्ता तालिका पर समेकन को सामान्य करने के लिए एक अच्छा कारण नहीं दिख रहा है।

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

100 पंक्तियों के क्रम के ऊपर, विदेशी चाबियों पर एक साधारण बीटी इंडेक्स थ्रूपुट में सभ्य और ध्यान देने योग्य वृद्धि कर सकता है।

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

केवल जब टेबल 1 मिलियन से अधिक रिकॉर्ड चला रहा था, तो हमें एक रीड प्रतिकृति का उपयोग करने पर विचार करना पड़ा।और वह तब होता है जब हम उन प्रक्रियाओं के बीच अंतर कर सकते हैं जो केवल कुछ तालिकाओं को पढ़ते हैं और लिखते नहीं हैं।

यदि आप Django का उपयोग कर रहे हैं, तो सावधान रहें जब आप उनके दस्तावेज़ों के अनुसार LIMIT लागू करते हैं; क्योंकि यह बहुत भ्रामक है। जब आप एक रिकॉर्ड सेट पर [: 100] (splice) करते हैं, तो आप SQL सर्वर पर वास्तव में भेजे गए SQL पर अपेक्षा नहीं करते हैं। मुझे यह पता लगाने में बहुत मुश्किल समय था। Django एक अच्छा विकल्प नहीं है जब आप ऐसा कुछ करने की योजना बनाते हैं जो बहुत बड़े पैमाने पर उगता है। लेकिन 1000 रिकॉर्ड के क्रम में, यह ठीक होगा।

संबंधित मुद्दे