2012-03-22 20 views
43

मैं बड़ी यादृच्छिक संख्याओं का उपयोग कुंजी के रूप में कर रहा हूं (किसी अन्य सिस्टम से आ रहा है)। काफी छोटे (जैसे कुछ मिलियन पंक्तियों में) टेबल पर सम्मिलन और अपडेट उचित लगता है उससे काफी लंबा समय ले रहा है।MySQL InnoDB इतना धीमा क्यों है?

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

यहाँ परिणाम हैं:

creating the MyISAM table took 0.000 seconds 
creating 1024000 rows of test data took 1.243 seconds 
inserting the test data took 6.335 seconds 
selecting 1023742 rows of test data took 1.435 seconds 
fetching 1023742 batches of test data took 0.037 seconds 
dropping the table took 0.089 seconds 
creating the InnoDB table took 0.276 seconds 
creating 1024000 rows of test data took 1.165 seconds 
inserting the test data took 3433.268 seconds 
selecting 1023748 rows of test data took 4.220 seconds 
fetching 1023748 batches of test data took 0.037 seconds 
dropping the table took 0.288 seconds 

MyISAM में डालने 1M पंक्तियां 6 सेकंड लेता है; इनो डीबी में 3433 सेकंड लेता है!

मैं क्या गलत कर रहा हूं? गलत कॉन्फ़िगर किया गया क्या है?

यहाँ परीक्षण कोड है (MySQL चूक के साथ एक सामान्य Ubuntu स्थापना है):

import sys, time, random 
import MySQLdb as db 

# usage: python script db_username db_password database_name 

db = db.connect(host="127.0.0.1",port=3306,user=sys.argv[1],passwd=sys.argv[2],db=sys.argv[3]).cursor() 

def test(engine): 

    start = time.time() # fine for this purpose 
    db.execute(""" 
CREATE TEMPORARY TABLE Testing123 (
k INTEGER PRIMARY KEY NOT NULL, 
v VARCHAR(255) NOT NULL 
) ENGINE=%s;"""%engine) 
    duration = time.time()-start 
    print "creating the %s table took %0.3f seconds"%(engine,duration) 

    start = time.time() 
    # 1 million rows in 100 chunks of 10K 
    data = [[(str(random.getrandbits(48)) if a&1 else int(random.getrandbits(31))) for a in xrange(10*1024*2)] for b in xrange(100)] 
    duration = time.time()-start 
    print "creating %d rows of test data took %0.3f seconds"%(sum(len(rows)/2 for rows in data),duration) 

    sql = "REPLACE INTO Testing123 (k,v) VALUES %s;"%("(%s,%s),"*(10*1024))[:-1] 
    start = time.time() 
    for rows in data: 
     db.execute(sql,rows) 
    duration = time.time()-start 
    print "inserting the test data took %0.3f seconds"%duration 

    # execute the query 
    start = time.time() 
    query = db.execute("SELECT k,v FROM Testing123;") 
    duration = time.time()-start 
    print "selecting %d rows of test data took %0.3f seconds"%(query,duration) 

    # get the rows in chunks of 10K 
    rows = 0 
    start = time.time() 
    while query: 
     batch = min(query,10*1024) 
     query -= batch 
     rows += len(db.fetchmany(batch)) 
    duration = time.time()-start 
    print "fetching %d batches of test data took %0.3f seconds"%(rows,duration) 

    # drop the table 
    start = time.time() 
    db.execute("DROP TABLE Testing123;") 
    duration = time.time()-start 
    print "dropping the table took %0.3f seconds"%duration 


test("MyISAM") 
test("InnoDB") 

उत्तर

33

InnoDB 'यादृच्छिक' प्राथमिक कुंजी के साथ अच्छी तरह से सामना नहीं कर रहा है के बाद

START TRANSACTION 

और इस:

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

कुछ संबंधित प्रश्नों

+2

> इसके लिए आपके मानक देखने में रुचि होगी! माईसाम: स्वत: वृद्धि कुंजी के साथ एक टेबल बनाना और फिर यादृच्छिक कुंजी फ़ील्ड में एक इंडेक्स जोड़ना लगभग उतना तेज़ है जितना जल्दी पहले यादृच्छिक फ़ील्ड के साथ तालिका बना रहा है; सभी 8 सेकंड के तहत। इनो डीबी: ऑटो-वृद्धि प्राथमिक कुंजी के साथ डालने से 54 सेकंड लगते हैं। फिर उस यादृच्छिक क्षेत्र पर एक इंडेक्स बनाना तो 214 सेकंड लेता है।धीमा, लेकिन * बड़े पैमाने पर * यादृच्छिक कुंजी के साथ डालने से तेज़ * तेज। – Will

+0

पॉल, अनुक्रमिक कुंजी के प्रदर्शन और लाभ के बारे में सामान्य प्रश्न: क्या इससे कोई फर्क नहीं पड़ता कि जब तक वे अभी भी क्रम में हैं तब तक कुंजी में अंतर हैं? यानी: 1, 5 10, 500, 1234, 7800 इत्यादि। मैंने चाबियों के लाभों पर बहुत सारी सामग्री पढ़ी है, लेकिन अगर अनुक्रमिक "केवल आरोही क्रम में (संभावित अंतराल के साथ) का अर्थ है, तो अनिश्चित हूं, या अगर अनुक्रमिक मतलब अंतराल नहीं है। उत्सुक क्योंकि यह एक बहु-सर्वर कुंजी जनरेशन सिस्टम से संबंधित है जिसका मैं उपयोग कर रहा हूं, जिसे मैं स्टैक ओवरफ्लो प्रश्न # 6338956 में बात करता हूं। धन्यवाद। – YeB

+6

यादृच्छिक कुंजी प्रविष्टियां इतनी धीमी हैं कि इनओडीबी एक प्राथमिक प्राथमिक कुंजी इंडेक्स के साथ पंक्ति डेटा का विशाल यादृच्छिक पूल रखने के बजाय प्राथमिक कुंजी क्रम में पंक्तियां संग्रहीत करता है। इसका अर्थ यह है कि यदि आप आईडी = 1 के साथ एक रिकॉर्ड (केवल) रिकॉर्ड करते हैं और आईडी = 10 के साथ एक और रिकॉर्ड, दोनों पंक्तियों के लिए डेटा को साइड-बाय-साइड संग्रहित किया जाता है। यदि आप आईडी = 5 के साथ एक रिकॉर्ड डालते हैं, तो InnoDB को आईडी = 10 के लिए डेटा को पूरे आईडी = 5 रिकॉर्ड को तालिका में रखने के तरीके से बाहर ले जाना है। ऐसा कई बार करें और आप पाएंगे कि * बहुत सारे डेटा स्थानांतरित हो जाते हैं-आसपास * बहुत * बार। यादृच्छिक कुंजी के साथ आप इसके बारे में कुछ भी नहीं कर सकते हैं। –

54

InnoDB, आप स्पष्ट लेनदेन उपयोग नहीं कर रहे तो InnoDB है प्रत्येक कथन के बाद एक प्रतिबद्ध करने के लिए लेन-देन का समर्थन करते हैं ("performs a log flush to disk for every insert")। आप पाश

COMMIT 
+3

मैंने इसे जोड़ा और यह अभी भी चल रहा है ... मुझे लगता है कि मैं 3000 सेकंड में आपको वापस ले जाऊंगा और ऐसा कहता हूं और आपको यह अलग नहीं बताता ...;) – Will

+3

यह अभी भी चल रहा है, इसलिए नहीं, यह नहीं है समस्या – Will

+2

यह मुझे बचाया। मुझे लगभग 9 मिलियन पंक्तियां डालना पड़ा - 24 घंटों के बाद यह केवल 10% पूर्ण था। मैंने इसे आपके पोस्ट के अनुसार एक लेनदेन के रूप में संशोधित किया और यह लगभग 2 घंटे में समाप्त हुआ! –

4

InnoDB के लिए डिफ़ॉल्ट मान वास्तव में बहुत बुरा है। InnoDB बहुत रैम निर्भर है, यदि आप सेटिंग्स को ट्वीक करते हैं तो आपको बेहतर परिणाम मिल सकता है। यहां एक गाइड है जिसका मैंने InnoDB optimization basic

19

का उपयोग किया है, मुझे एक साथ MyISAM और InnoDB दोनों में एक सम्मिलित-भारी एप्लिकेशन का परीक्षण करने की आवश्यकता है। एक ऐसी सेटिंग थी जो मेरे द्वारा किए गए गति के मुद्दों को हल करती थी। निम्नलिखित सेट करके देखें:

innodb_flush_log_at_trx_commit = 2 

सुनिश्चित करें कि आप स्थापित करने here बारे में पढ़कर जोखिम को समझते हैं।

इसके अलावा https://dba.stackexchange.com/questions/12611/is-it-safe-to-use-innodb-flush-log-at-trx-commit-2/12612 और https://dba.stackexchange.com/a/29974/9405

+0

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

5

मैं अपने सिस्टम पर बहुत अलग परिणाम प्राप्त देखते हैं, लेकिन इस चूक का उपयोग नहीं कर रहा है। आप संभवतः innodb-log-file-size पर बाधित हैं, जो डिफ़ॉल्ट रूप से 5 एम है।पर InnoDB-लॉग-फ़ाइल आकार = 100M मैं इस तरह के परिणाम (सभी नंबरों को सेकंड में कर रहे हैं):

       MyISAM  InnoDB 
create table     0.001  0.276 
create 1024000 rows   2.441  2.228 
insert test data    13.717  21.577 
select 1023751 rows   2.958  2.394 
fetch 1023751 batches   0.043  0.038 
drop table     0.132  0.305 

innodb-log-file-size बढ़ाने से कुछ ही सेकंड से इस तेज़ हो जाएगी। innodb-flush-log-at-trx-commit=2 या 0 सेट करके स्थायित्व गारंटी को छोड़कर कुछ हद तक सम्मिलित संख्या में भी सुधार होगा।

2

आपका innodb बफर-पूल आकार क्या है? सुनिश्चित करें कि आपने इसे अपनी रैम का 75% सेट कर दिया है। आमतौर पर इनो डीबी के प्राथमिक कुंजी ऑर्डर में प्रविष्टियां बेहतर होती हैं। लेकिन एक बड़े पूल आकार के साथ, आपको अच्छी गति देखना चाहिए।

1

चीजें हैं जो आवेषण में तेजी लाने के:

  • मैं खाली तालिका
  • में बड़े डालने से पहले एक मेज से सभी चाबियाँ हटा दिया था तो पाया मैं एक समस्या यह है कि सूचकांक स्मृति में फिट नहीं था।
  • यह भी पाया कि मुझे bin_binlog = 0 (1 होना चाहिए) भले ही binlog का उपयोग नहीं किया गया हो।
  • यह भी पाया मैं innodb_buffer_pool_instances
-1

mysql 5.7 सेट नहीं किया: मैं अभी एक परीक्षण किया था और मैं यादृच्छिक प्राथमिक कुंजी और ऑटो वृद्धि एक के बीच किसी भी ध्यान देने अंतर नोटिस नहीं किया था।

2

यह एक पुराना विषय है लेकिन अक्सर खोजा जाता है। इतने लंबे समय के रूप में आप पिछले एक दूसरे या ऐसा है, बड़े पैमाने पर अपडेट करने से पहले, आप निर्धारित कर सकते हैं इन वैश्विक मानकों में प्रतिबद्ध लेनदेन को खोने का जोखिम (जैसा कि ऊपर @philip कोशी ने कहा) के बारे में पता कर रहे हैं

innodb-flush-log-at-trx-commit=0 
sync_binlog=0 

तो तो फिर से चालू अद्यतन पूरा होने के बाद (यदि वांछित है)।

innodb-flush-log-at-trx-commit=1 
sync_binlog=1 

पूर्ण एसीआईडी ​​अनुपालन के लिए।

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

update/insert पर असर डालने वाली एक और चीज पूरी तरह से पूर्ण पाठ अनुक्रमणिका है। एक मामले में, दो टेक्स्ट फ़ील्ड वाली एक तालिका जिसमें पूर्ण टेक्स्ट इंडेक्स होता है, 2 मिली पंक्तियों को डालने में 6 घंटे लगते हैं और पूर्ण पाठ अनुक्रमणिका हटा दिए जाने के बाद केवल 10 मिनट लगते हैं। अधिक अनुक्रमणिका, अधिक समय। तो बड़े पैमाने पर आवेषण/अपडेट से पहले अनन्य और प्राथमिक कुंजी के अलावा खोज अनुक्रमणिका हटा दी जा सकती हैं।

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