कौन सा तेज़ है: एकाधिक एकल INSERT या एक बहु-पंक्ति INSERT?


183

मैं अपने कोड के एक हिस्से को अनुकूलित करने का प्रयास कर रहा हूं जो MySQL में डेटा सम्मिलित करता है। क्या मुझे एक बड़ी बहु-पंक्ति INSERT बनाने के लिए INSERTs को चेन करना चाहिए या कई अलग-अलग INSERT को तेज करना चाहिए?

जवाबों:


287

https://dev.mysql.com/doc/refman/8.0/en/insert-optimization.html

एक पंक्ति सम्मिलित करने के लिए आवश्यक समय निम्नलिखित कारकों द्वारा निर्धारित किया जाता है, जहां संख्या अनुमानित अनुपात दर्शाती है:

  • कनेक्टिंग: (3)
  • सर्वर को क्वेरी भेजना: (2)
  • पार्सिंग क्वेरी: (2)
  • पंक्ति सम्मिलित करना: (पंक्ति का 1 × आकार)
  • अनुक्रमणिका सम्मिलित करना: (अनुक्रमणिका का 1 × संख्या)
  • समापन: (1)

इससे यह स्पष्ट होना चाहिए, कि एक बड़ा बयान भेजने से आपको 7 प्रति ओवरवेट स्टेटमेंट की बचत होगी, जो आगे के पाठ को भी पढ़ता है:

यदि आप एक ही समय में एक ही क्लाइंट से कई पंक्तियों को सम्मिलित कर रहे हैं, तो एक बार में कई पंक्तियों को सम्मिलित करने के लिए कई VALUES सूचियों के साथ INSERT कथनों का उपयोग करें। यह अलग-अलग एकल-पंक्ति INSERT कथनों का उपयोग करने की तुलना में काफी तेज (कुछ मामलों में कई गुना तेज) है।


27
यदि एक ही डेटाबेस लेनदेन में एक से अधिक INSERTs हों तो यह उत्तर कैसे लागू होता है?
चुटकी

2
सिंगल इंसर्ट स्टेटमेंट का उपयोग करके मैं एक समय में कितनी पंक्तियाँ सम्मिलित कर सकता हूँ। क्या यह मुझे एक बार में 10000 पंक्तियाँ डालने की अनुमति देता है?
नरेश रामोलिया

10
@Pinch ~ 1.5k upserts (इंसर्ट / अपडेट्स) करते समय एक ट्रांजेक्शन का उपयोग करने से ऑपरेशन के ~ 1.5 सेकंड से ~ 0.2 सेकंड तक का समय कम हो जाता है। या दूसरे शब्दों में, एकल-पंक्ति आवेषण की तुलना में यह 86% तेज हो गया। अरे नहीं।
fgblomqvist

1
नोट: MSSQL में बहुत भिन्न
प्रतीत होता है

दोहराव वाले कई एकल आवेषण डालने के लिए तैयार स्टेटमेंट का उपयोग करने के बारे में कैसे?
प्रियाबागस

151

मुझे पता है कि मैं इस प्रश्न का उत्तर लगभग ढाई साल बाद दे रहा था, लेकिन मैं अभी एक प्रोजेक्ट से कुछ कठिन डेटा प्रदान करना चाहता था, जो मैं अभी काम कर रहा हूं, जिससे पता चलता है कि वास्तव में प्रति मिनट कई VALUE ब्लॉक कर रहा है MUCH अनुक्रमिक एकल VALUE ब्लॉक INSERT कथनों से तेज।

C # में इस बेंचमार्क के लिए मैंने जो कोड लिखा था, वह MSSQL डेटा स्रोत (~ 19,000 पंक्तियों, जो किसी भी लेखन शुरू होने से पहले पढ़े जाते हैं), और MySql .NET कनेक्टर (Mysql.Data।) सामान से मेमोरी में डेटा पढ़ने के लिए ODBC का उपयोग करता है। तैयार बयानों के माध्यम से MySQL सर्वर पर एक टेबल में मेमोरी से डेटा को सम्मिलित करें। यह इस तरह से लिखा गया था, ताकि मुझे तैयार INSERT के प्रति VALUE ब्लॉकों की संख्या को गतिशील रूप से समायोजित करने की अनुमति दी जा सके (अर्थात, एक समय में n पंक्तियों को सम्मिलित करें, जहां मैं एक रन से पहले n के मूल्य को समायोजित कर सकता था।) मैंने भी परीक्षण चलाया। प्रत्येक एन के लिए कई बार।

सिंगल वैल्यू ब्लॉक करना (जैसे, एक बार में 1 पंक्ति) को चलाने में 5.7 - 5.9 सेकंड लगे। अन्य मूल्य इस प्रकार हैं:

एक समय में 2 पंक्तियाँ: एक समय में 3.5 - 3.5 सेकंड
5 पंक्तियाँ: एक समय में 2.2 - 2.2 सेकंड
10 पंक्तियाँ: एक समय में 1.7 - 1.7 सेकंड
50 पंक्तियाँ: 1.17 - 1.18 सेकंड
एक समय में 100 पंक्तियाँ: 1.1 - 1.4 सेकंड
एक समय में 500 पंक्तियाँ: एक समय में 1.1 - 1.2 सेकंड
1000 पंक्तियाँ: 1.17 - 1.17 सेकंड

तो हां, यहां तक ​​कि सिर्फ 2 या 3 को एक साथ लिखने से गति में नाटकीय सुधार होता है (एन के एक कारक द्वारा रनटाइम कट), जब तक आप n = 5 और n = 10 के बीच कहीं नहीं पहुंचते, जिस बिंदु पर सुधार स्पष्ट रूप से बंद हो जाता है, और कहीं n = 10 से n = 50 सीमा में सुधार नगण्य हो जाता है।

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


1
स्पष्टीकरण अनुरोध: आपका समय "प्रति सेकंड सेकंड" या "कुल सेकंड" है।
EngrStudent

3
कुल सेकंड - तो प्रति सेकंड सेकंड कि ~ 19,000 पंक्तियों से विभाजित है। हालांकि यह एक छोटी संख्या है, इसलिए यदि आप आसानी से तुलनीय संख्या की तलाश कर रहे हैं तो शायद पंक्तियाँ / सेकंड एक बेहतर मीट्रिक है।
जॉन क्लोसे

संयोग से, मेरा इस संबंधित उत्तर पर वर्णित दृष्टिकोण के लिए कुछ उदाहरण .NET कोड है: stackoverflow.com/questions/25377357/…
जॉन क्लोसके

18

एक प्रमुख कारक यह होगा कि क्या आप एक ट्रांजेक्शनल इंजन का उपयोग कर रहे हैं और क्या आपके पास ऑटोकॉमिट है।

स्वतः पूर्णता डिफ़ॉल्ट रूप से चालू है और आप संभवतः इसे छोड़ना चाहते हैं; इसलिए, प्रत्येक सम्मिलित जो आप करते हैं वह अपना लेनदेन करता है। इसका मतलब है कि यदि आप प्रति पंक्ति एक सम्मिलित करते हैं, तो आप प्रत्येक पंक्ति के लिए लेनदेन करने जा रहे हैं।

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

मैं निश्चित रूप से मान रहा हूं कि आप एक ट्रांजेक्शनल इंजन का उपयोग कर रहे हैं (आमतौर पर निर्दोष) और यह कि आपने स्थायित्व को कम करने के लिए सेटिंग्स को ट्विक नहीं किया है।

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

दूसरी ओर, अपशॉट यह है कि आप बहु-पंक्ति आवेषण का उपयोग करना चाहते हैं।

एक सीमा है जिस पर वह प्रति-उत्पादक हो जाता है, लेकिन ज्यादातर मामलों में यह कम से कम 10,000 पंक्तियों का होता है। इसलिए यदि आप उन्हें 1,000 पंक्तियों तक बैचते हैं, तो आप शायद सुरक्षित हैं।

यदि आप MyISAM का उपयोग कर रहे हैं, तो चीजों का एक पूरा भार है, लेकिन मैं आपको उन लोगों के साथ बोर नहीं करूंगा। शांति।


1
वहाँ किसी भी कारण से यह एक बिंदु के बाद काउंटर उत्पादक हो जाता है? मैंने देखा है यह पहले भी होता है, लेकिन यह निश्चित नहीं था कि क्यों।
ध्रुव गरोला

1
क्या आप जानते हैं कि लेनदेन का उपयोग करते समय MySQL आवेषण को बैचने में कोई बिंदु है । अगर मैं अपने अंतर्निहित पुस्तकालय (जावा JDBC - mysql-कनेक्टर-जावा-5.1.30) को वास्तव में तब तक कमिट नहीं कर रहा हूं, जब तक कि मैं इसे नहीं बताऊं।
RTF

@ आरटीएफ मुझे लगता है कि आपको अपनी स्थिति में उस व्यवहार को निर्धारित करने के लिए एक छोटा परीक्षण करने की आवश्यकता होगी क्योंकि यह अत्यधिक कार्यान्वयन विशिष्ट व्यवहार है, लेकिन कई मामलों में हां लेनदेन को समान प्रदर्शन लाभ प्रदान करना चाहिए।
चमेली हेगमैन

9

संभव के रूप में एक समय में तार में कई आवेषण भेजें। वास्तविक सम्मिलित गति समान होनी चाहिए, लेकिन आप नेटवर्क ओवरहेड की कमी से प्रदर्शन लाभ देखेंगे।


7

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


क्या होगा अगर लगातार कनेक्शन का उपयोग किया जाता है?
dusoft

6
अभी भी ओवरहेड है। यदि आप हजारों आवेषण कर रहे हैं तो ट्रांजिट टाइम अकेले (प्रत्येक अलग-अलग इंसर्ट के लिए) से और जल्दी से बोधगम्य होगा।
आरसी।

4

हो सकता है कि आप यह चाहते हों :

  • जांचें कि ऑटो-कमिट बंद है
  • कनेक्शन खोलें
  • एक ही लेन-देन में आवेषण के कई बैच भेजें (लगभग 4000-10000 पंक्तियों का आकार? आप देखें)
  • निकट संबंध

यह निर्भर करता है कि आपका सर्वर कितना अच्छा है (इसकी निश्चित रूप से ठीक है PostgreSQl, Oracleऔर MSSQL), एकाधिक थ्रेड और कई कनेक्शन के साथ ऊपर की बात करें।


3

सामान्य तौर पर, कनेक्शन ओवरहेड होने के कारण कई आवेषण धीमे होंगे। एक साथ कई आवेषण करने से ओवरहेड की लागत प्रति इंसर्ट कम हो जाएगी।

आप किस भाषा का उपयोग कर रहे हैं, इसके आधार पर, आप संभवतः db पर जाने से पहले अपनी प्रोग्रामिंग / स्क्रिप्टिंग भाषा में एक बैच बना सकते हैं और प्रत्येक प्रविष्टि को बैच में जोड़ सकते हैं। तब आप एक कनेक्ट ऑपरेशन का उपयोग करके एक बड़े बैच को निष्पादित करने में सक्षम होंगे। यहाँ जावा में एक उदाहरण है।


3

MYSQL 5.5 एक sql इन्सर्ट स्टेटमेंट में ~ 300 से ~ 450ms लगे। नीचे दिए गए आँकड़े इनलाइन मल्टीपल इन्सर्ट स्टेटमेंट के लिए हैं।

(25492 row(s) affected)
Execution Time : 00:00:03:343
Transfer Time  : 00:00:00:000
Total Time     : 00:00:03:343

मैं कहूंगा कि इनलाइन जाने का रास्ता है :)


0

यह हास्यास्पद है कि जब आवेषण की बात आती है तो माईसकल और मारियाडीबी को कितना बुरा लगता है। मैंने mysql 5.7 और mariadb 10.3 का परीक्षण किया, उन पर कोई वास्तविक अंतर नहीं था।

मैंने इसे NVME डिस्क, 70,000 IOPS, 1.1 GB / sec seq throughput के साथ एक सर्वर पर परीक्षण किया है और यह पूर्ण द्वैध (पढ़ने और लिखने) संभव है।
सर्वर एक उच्च प्रदर्शन सर्वर है।
यह 20 GB RAM दिया।
डेटाबेस पूरी तरह से खाली।

मल्टी रो इन्सर्ट करते समय मुझे प्राप्त होने वाली गति 5000 आवेषण प्रति सेकंड थी (इसे 1 एमबी के साथ 10 एमबी तक के डेटा के साथ आज़माया गया)

अब सुराग:
यदि मैं एक और धागा जोड़ता हूं और एक ही तालिका में सम्मिलित करता हूं तो मेरे पास अचानक 2x5000 / सेकंड है। एक और धागा और मेरे पास कुल 15000 / सेकंड है

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

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


@ क्राफ्ट आपको बाहरी विकास की आवश्यकता है, यह mysql के भीतर नहीं किया जा सकता है। थ्रेड्स का अर्थ है कि आप सर्वर से कई कनेक्शन का उपयोग करते हैं, आप क्वेरी को कई विखंडों में विभाजित करते हैं (उदाहरण के लिए इसे प्राथमिक कुंजी द्वारा भागों में विभाजित करके)। मैं बहुत बड़े तालिकाओं पर इस पद्धति का उपयोग करके 10,000 गुना तक प्रदर्शन करने में कामयाब रहा। 40,000 सेकंड तक चलने वाली क्वेरी 2-3 मिनट में समाप्त हो सकती हैं। यदि आप कई थ्रेड्स का उपयोग करते हैं और आपका mysql अत्यधिक अनुकूलित है।
जॉन

@ जॉन दिलचस्प और कुछ वास्तविक अच्छे अनुप्रयोग हो सकते हैं ... लेकिन ... यदि आप क्वेरी को कई विखंडों में विभाजित करते हैं तो आप लेनदेन कैसे संभालते हैं? और निम्नलिखित परिदृश्य पर भी विचार करें: टेबल x में एक 'पैरेंट_ड' कॉलम है जो एक ही टेबल 'आईडी' से संबंधित है। आपके डेटा के अंदर कहीं आपके पास INSERT INTO x ( id,, parent_idVALUES (1, NULL) है। मानों के अगले सेट में से एक उस पंक्ति से लिंक करता है। यदि आप विखंडू में विभाजित हो जाते हैं और उस सेट को दूसरे चंक में ले जाया जाता है, तो इसे पहली प्रक्रिया से पहले संसाधित किया जा सकता है, पूरी प्रक्रिया को विफल कर सकता है। किसी भी विचार से कैसे निपटना है?
zozo

@zozo यह थोक आवेषण और थोक प्रश्नों के लिए उपयोगी है। लेन-देन वैसे भी प्रदर्शन को बर्बाद कर देते हैं क्योंकि उनमें डेटा बफ़रिंग शामिल होती है। लेकिन आप बहु थ्रेडेड आवेषण या प्रश्नों में लेनदेन का उपयोग कर सकते हैं।
जॉन

-2

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

SET FOREIGN_KEY_CHECKS=0;

ऑफकोर्स आपको इसे आवेषण के बाद वापस चालू करना चाहिए:

SET FOREIGN_KEY_CHECKS=1;

यह विशाल डेटा सम्मिलित करने का सामान्य तरीका है। विदेशी प्रमुख जांच को अक्षम करने से पहले आप डेटा की अखंडता को तोड़ सकते हैं।


1
कोई कारण नहीं कि दो कारणों से ppl ने इसे क्यों उतारा: 1. इसका सवाल से कोई लेना-देना नहीं है। यह वास्तव में एक बुरा विचार है (कुछ अपवादों के साथ - जैसे डंपिंग या संरचनात्मक अस्थायी परिवर्तन - लेकिन सामान्य रूप से खराब)। चेक एक कारण के लिए हैं: वे डेटा स्थिरता सुनिश्चित करने के लिए वहां हैं। वे चीजों को धीमा कर देते हैं क्योंकि वे सुनिश्चित करते हैं कि आप सम्मिलित नहीं करते हैं या अन्यथा डेटा नहीं बदलते हैं जो आपको नहीं करना चाहिए। प्रश्नों को सही तरीके से अनुकूलित करने का प्रयास करें; किसी भी व्यवसायिक महत्वपूर्ण माहौल में इसका मतलब होगा कि आप किसी भी बिंदु पर विफल होंगे, इस बात पर ध्यान दिए बिना कि आप कितनी सावधानी बरतेंगे।
zozo

1
हो सकता है लेकिन यह विकल्प बड़े तालिकाओं और बहुत व्यावहारिक आयात करने में अत्यधिक प्रभावी है और यह कुछ लोगों को यह अनुमान दे सकता है कि वे डेटा प्रविष्टि को बहुत तेज़ी से कैसे बना सकते हैं।
एमएसएस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.