2011-07-21 11 views
36

मेरे पास एक छोटी सी लिपि है जो स्कैला में लिखी गई है जिसका उद्देश्य 100,000,000 नमूना रिकॉर्ड के साथ एक मोंगोडीबी उदाहरण लोड करना है। विचार डीबी को सभी लोड करने के लिए है, और उसके बाद कुछ प्रदर्शन परीक्षण करें (और यदि आवश्यक हो तो ट्यून/पुनः लोड करें)।प्रदर्शन परीक्षण के लिए स्काला के साथ मोंगोडीबी में 100 मिलियन रिकॉर्ड कैसे लोड करें?

समस्या यह है कि प्रति 100,000 रिकॉर्ड लोड-टाइम काफी रैखिक रूप से बढ़ता है। मेरी लोड प्रक्रिया की शुरुआत में उन रिकॉर्ड्स को लोड करने में केवल 4 सेकंड लग गए। अब, लगभग 6,000,000 रिकॉर्ड पर, यह एक ही राशि (100,000) लोड करने के लिए 300 से 400 सेकंड के बीच ले रहा है! धीरे-धीरे परिमाण के दो आदेश हैं! प्रश्न अभी भी snappy हैं, लेकिन इस दर पर, मैं कभी भी डेटा की मात्रा लोड करने में सक्षम नहीं होगा।

यदि यह मेरे सभी रिकॉर्ड (सभी 100,000,000!) के साथ फ़ाइल लिखता है, तो यह तेजी से काम करेगा, और फिर पूरी चीज को आयात करने के लिए mongoimport का उपयोग करें? या मेरी अपेक्षाएं बहुत अधिक हैं और मैं डीबी का उपयोग कर रहा हूं जो इसे संभालने वाला है?

कोई विचार? धन्यवाद!

import java.util.Date 

import com.mongodb.casbah.Imports._ 
import com.mongodb.casbah.commons.MongoDBObject 

object MongoPopulateTest { 
    val ONE_HUNDRED_THOUSAND = 100000 
    val ONE_MILLION   = ONE_HUNDRED_THOUSAND * 10 

    val random  = new scala.util.Random(12345) 
    val connection = MongoConnection() 
    val db   = connection("mongoVolumeTest") 
    val collection = db("testData") 

    val INDEX_KEYS = List("A", "G", "E", "F") 

    def main(args: Array[String]) { 
    populateCoacs(ONE_MILLION * 100) 
    } 

    def populateCoacs(count: Int) { 
    println("Creating indexes: " + INDEX_KEYS.mkString(", ")) 
    INDEX_KEYS.map(key => collection.ensureIndex(MongoDBObject(key -> 1))) 

    println("Adding " + count + " records to DB.") 

    val start  = (new Date()).getTime() 
    var lastBatch = start 

    for(i <- 0 until count) { 
     collection.save(makeCoac()) 
     if(i % 100000 == 0 && i != 0) { 
     println(i + ": " + (((new Date()).getTime() - lastBatch)/1000.0) + " seconds (" + (new Date()).toString() + ")") 
     lastBatch = (new Date()).getTime() 
     } 
    } 

    val elapsedSeconds = ((new Date).getTime() - start)/1000 

    println("Done. " + count + " COAC rows inserted in " + elapsedSeconds + " seconds.") 
    } 

    def makeCoac(): MongoDBObject = { 
    MongoDBObject(
     "A" -> random.nextPrintableChar().toString(), 
     "B" -> scala.math.abs(random.nextInt()), 
     "C" -> makeRandomPrintableString(50), 
     "D" -> (if(random.nextBoolean()) { "Cd" } else { "Cc" }), 
     "E" -> makeRandomPrintableString(15), 
     "F" -> makeRandomPrintableString(15), 
     "G" -> scala.math.abs(random.nextInt()), 
     "H" -> random.nextBoolean(), 
     "I" -> (if(random.nextBoolean()) { 41 } else { 31 }), 
     "J" -> (if(random.nextBoolean()) { "A" } else { "B" }), 
     "K" -> random.nextFloat(), 
     "L" -> makeRandomPrintableString(15), 
     "M" -> makeRandomPrintableString(15), 
     "N" -> scala.math.abs(random.nextInt()), 
     "O" -> random.nextFloat(), 
     "P" -> (if(random.nextBoolean()) { "USD" } else { "GBP" }), 
     "Q" -> (if(random.nextBoolean()) { "PROCESSED" } else { "UNPROCESSED" }), 
     "R" -> scala.math.abs(random.nextInt()) 
    ) 
    } 

    def makeRandomPrintableString(length: Int): String = { 
    var result = "" 
    for(i <- 0 until length) { 
     result += random.nextPrintableChar().toString() 
    } 
    result 
    } 
} 

यहाँ मेरी स्क्रिप्ट से उत्पादन है::

Creating indexes: A, G, E, F 
Adding 100000000 records to DB. 
100000: 4.456 seconds (Thu Jul 21 15:18:57 EDT 2011) 
200000: 4.155 seconds (Thu Jul 21 15:19:01 EDT 2011) 
300000: 4.284 seconds (Thu Jul 21 15:19:05 EDT 2011) 
400000: 4.32 seconds (Thu Jul 21 15:19:10 EDT 2011) 
500000: 4.597 seconds (Thu Jul 21 15:19:14 EDT 2011) 
600000: 4.412 seconds (Thu Jul 21 15:19:19 EDT 2011) 
700000: 4.435 seconds (Thu Jul 21 15:19:23 EDT 2011) 
800000: 5.919 seconds (Thu Jul 21 15:19:29 EDT 2011) 
900000: 4.517 seconds (Thu Jul 21 15:19:33 EDT 2011) 
1000000: 4.483 seconds (Thu Jul 21 15:19:38 EDT 2011) 
1100000: 4.78 seconds (Thu Jul 21 15:19:43 EDT 2011) 
1200000: 9.643 seconds (Thu Jul 21 15:19:52 EDT 2011) 
1300000: 25.479 seconds (Thu Jul 21 15:20:18 EDT 2011) 
1400000: 30.028 seconds (Thu Jul 21 15:20:48 EDT 2011) 
1500000: 24.531 seconds (Thu Jul 21 15:21:12 EDT 2011) 
1600000: 18.562 seconds (Thu Jul 21 15:21:31 EDT 2011) 
1700000: 28.48 seconds (Thu Jul 21 15:21:59 EDT 2011) 
1800000: 29.127 seconds (Thu Jul 21 15:22:29 EDT 2011) 
1900000: 25.814 seconds (Thu Jul 21 15:22:54 EDT 2011) 
2000000: 16.658 seconds (Thu Jul 21 15:23:11 EDT 2011) 
2100000: 24.564 seconds (Thu Jul 21 15:23:36 EDT 2011) 
2200000: 32.542 seconds (Thu Jul 21 15:24:08 EDT 2011) 
2300000: 30.378 seconds (Thu Jul 21 15:24:39 EDT 2011) 
2400000: 21.188 seconds (Thu Jul 21 15:25:00 EDT 2011) 
2500000: 23.923 seconds (Thu Jul 21 15:25:24 EDT 2011) 
2600000: 46.077 seconds (Thu Jul 21 15:26:10 EDT 2011) 
2700000: 104.434 seconds (Thu Jul 21 15:27:54 EDT 2011) 
2800000: 23.344 seconds (Thu Jul 21 15:28:17 EDT 2011) 
2900000: 17.206 seconds (Thu Jul 21 15:28:35 EDT 2011) 
3000000: 19.15 seconds (Thu Jul 21 15:28:54 EDT 2011) 
3100000: 14.488 seconds (Thu Jul 21 15:29:08 EDT 2011) 
3200000: 20.916 seconds (Thu Jul 21 15:29:29 EDT 2011) 
3300000: 69.93 seconds (Thu Jul 21 15:30:39 EDT 2011) 
3400000: 81.178 seconds (Thu Jul 21 15:32:00 EDT 2011) 
3500000: 93.058 seconds (Thu Jul 21 15:33:33 EDT 2011) 
3600000: 168.613 seconds (Thu Jul 21 15:36:22 EDT 2011) 
3700000: 189.917 seconds (Thu Jul 21 15:39:32 EDT 2011) 
3800000: 200.971 seconds (Thu Jul 21 15:42:53 EDT 2011) 
3900000: 207.728 seconds (Thu Jul 21 15:46:21 EDT 2011) 
4000000: 213.778 seconds (Thu Jul 21 15:49:54 EDT 2011) 
4100000: 219.32 seconds (Thu Jul 21 15:53:34 EDT 2011) 
4200000: 241.545 seconds (Thu Jul 21 15:57:35 EDT 2011) 
4300000: 193.555 seconds (Thu Jul 21 16:00:49 EDT 2011) 
4400000: 190.949 seconds (Thu Jul 21 16:04:00 EDT 2011) 
4500000: 184.433 seconds (Thu Jul 21 16:07:04 EDT 2011) 
4600000: 231.709 seconds (Thu Jul 21 16:10:56 EDT 2011) 
4700000: 243.0 seconds (Thu Jul 21 16:14:59 EDT 2011) 
4800000: 310.156 seconds (Thu Jul 21 16:20:09 EDT 2011) 
4900000: 318.421 seconds (Thu Jul 21 16:25:28 EDT 2011) 
5000000: 378.112 seconds (Thu Jul 21 16:31:46 EDT 2011) 
5100000: 265.648 seconds (Thu Jul 21 16:36:11 EDT 2011) 
5200000: 295.086 seconds (Thu Jul 21 16:41:06 EDT 2011) 
5300000: 297.678 seconds (Thu Jul 21 16:46:04 EDT 2011) 
5400000: 329.256 seconds (Thu Jul 21 16:51:33 EDT 2011) 
5500000: 336.571 seconds (Thu Jul 21 16:57:10 EDT 2011) 
5600000: 398.64 seconds (Thu Jul 21 17:03:49 EDT 2011) 
5700000: 351.158 seconds (Thu Jul 21 17:09:40 EDT 2011) 
5800000: 410.561 seconds (Thu Jul 21 17:16:30 EDT 2011) 
5900000: 689.369 seconds (Thu Jul 21 17:28:00 EDT 2011) 
+0

आपके डेटा को कम से कम 8 गीगाबाइट मेमोरी की तरह उपयोग करना चाहिए। यहां तक ​​कि सूचकांक में कम से कम आधा गीगाबाइट लेना चाहिए। क्या आप सुनिश्चित करते हैं कि डीबी इसे रैम में फिट कर सकता है? मैं किसी भी माध्यम से एक मोंगोडीबी विशेषज्ञ नहीं हूं, लेकिन मुझे लगता है कि स्वैपिंग के कारण यह धीमा हो सकता है। – Madoc

+4

* डेटा डालने के बाद * इंडेक्स जोड़ने का प्रयास करें, इससे सम्मिलन प्रदर्शन में सुधार होना चाहिए। – pingw33n

उत्तर

49

कुछ युक्तियां:

  1. डालने, आवेषण सूचकांक जो एक ओवरहेड है संशोधित रूप में पहले नहीं सूचकांक अपने संग्रह मत करो। सब कुछ डालें, फिर इंडेक्स बनाएं।

  2. "सेव" के बजाय, mongoDB "बैचिनर्ट" का उपयोग करें जो 1 ऑपरेशन में कई रिकॉर्ड डाल सकता है। तो प्रति बैच लगभग 5000 दस्तावेज डाले गए हैं। आपको उल्लेखनीय प्रदर्शन लाभ दिखाई देगा।

    here डालने की विधि # 2 देखें, यह दस्तावेज़ के बजाय डालने के लिए दस्तावेज़ों की सरणी लेता है। इसके अलावा this thread

    में चर्चा को देखें और अगर आप बेंचमार्क के लिए और अधिक चाहते हैं -

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

+1

अच्छा। मैं 5000 प्रति डालने (और कोई अनुक्रमणिका नहीं) के बैचों के साथ casbah collection.insert (सूची [MongoDBObject] (...)) का उपयोग कर प्रति 100k वस्तुओं प्रति ~ 5 सेकंड पर हूँ। कुछ ही मिनटों में अब 15 मिलियन से अधिक किया गया है। पहले उसी नंबर पर जाने के लिए, मुझे इसे रात भर चलाना पड़ा। धन्यवाद! –

+2

100 मिलियन 1 घंटे और 20 मिनट में लोड किया गया। चार सूचकांक में से प्रत्येक को बनाने के लिए लगभग एक घंटे लगते हैं, इसलिए इसे लगभग 5 घंटे लगाना चाहिए। बुरा नहीं। एक बार फिर धन्यवाद। –

+0

बहुत अच्छा लगता है। आपका स्वागत है । – DhruvPathak

6

मैं एक ही बात किया है

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

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

जैसे ही आप डेटा लोड कर रहे हैं, उपलब्ध स्मृति के साथ db.collection.totalIndexSize() की तुलना करने का प्रयास करें, और आपको शायद यह दिखाई देगा।

आपकी सर्वश्रेष्ठ शर्त के बाद इंडेक्स बनाने के लिए है, आपने डेटा लोड किया है। हालांकि, यह अभी भी समस्या का समाधान नहीं करता है जब यह आवश्यक _id इंडेक्स है जिसमें एक यादृच्छिक मान (GUID, हैश इत्यादि) होता है, तो आपका सबसे अच्छा तरीका शेरिंग या अधिक रैम प्राप्त करने के बारे में सोचना पड़ सकता है।

4

मैंने अपनी परियोजना में जो कुछ किया वह मल्टीथ्रेडिंग का थोड़ा सा जोड़ रहा था (परियोजना सी # में है, लेकिन मुझे उम्मीद है कि कोड स्वयं स्पष्टीकरणपूर्ण है)। धागे की जरूरी संख्या के साथ खेलने के बाद यह पता चला कि कोर की संख्या में धागे की संख्या को थोड़ा बेहतर प्रदर्शन (10-20%) की ओर जाता है, लेकिन मुझे लगता है कि यह बढ़ावा हार्डवेयर विशिष्ट है। यहाँ कोड है:

public virtual void SaveBatch(IEnumerable<object> entities) 
    { 
     if (entities == null) 
      throw new ArgumentNullException("entities"); 

     _repository.SaveBatch(entities); 
    } 


    public void ParallelSaveBatch(IEnumerable<IEnumerable<object>> batchPortions) 
    { 
     if (batchPortions == null) 
      throw new ArgumentNullException("batchPortions"); 
     var po = new ParallelOptions 
       { 
        MaxDegreeOfParallelism = Environment.ProcessorCount 
       }; 
     Parallel.ForEach(batchPortions, po, SaveBatch); 
    } 
0

एक अन्य विकल्प TokuMX कोशिश करने के लिए है। वे फ्रैक्टल इंडेक्स का उपयोग करते हैं जिसका अर्थ है कि it does not slow down over time as the database gets bigger

टोकूएमएक्स को मोंगोडीबी के आने वाले संस्करण में कस्टम स्टोरेज ड्राइवर के रूप में शामिल करने जा रहा है।

मोंगोडीबी का वर्तमान संस्करण लिनक्स के तहत चलता है। मैं का उपयोग कर विंडोज़ पर बहुत तेजी से चल रहा था।

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