PostgreSQL में प्रविष्टि के प्रदर्शन को गति कैसे दें


215

मैं परीक्षण प्रविष्टि प्रविष्टि प्रदर्शन का परीक्षण कर रहा हूं। मेरे पास एक कॉलम है जिसमें एक कॉलम है जिसमें उसका डेटा टाइप है। इस पर एक सूचकांक भी है। मैंने इस क्वेरी का उपयोग करके डेटाबेस भरा:

insert into aNumber (id) values (564),(43536),(34560) ...

मैंने ऊपर की क्वेरी के साथ एक बार में बहुत जल्दी 10,000 मिलियन पंक्तियाँ डालीं। डेटाबेस के 6 मिलियन पंक्तियों के प्रदर्शन तक पहुंचने के बाद, प्रत्येक 15 मिनट में 1 मिलियन पंक्तियों में काफी गिरावट आई। प्रविष्टि प्रदर्शन को बढ़ाने के लिए कोई चाल है? मुझे इस परियोजना पर इष्टतम प्रविष्टि प्रदर्शन की आवश्यकता है।

5 जीबी रैम वाली मशीन पर विंडोज 7 प्रो का उपयोग करना।


5
यह सवालों में भी अपने पीजी संस्करण का उल्लेख करने लायक है। इस मामले में यह बहुत अंतर नहीं करता है, लेकिन यह बहुत सारे सवालों के लिए करता है।
क्रेग रिंगर

1
तालिका पर अनुक्रमणिका ड्रॉप करें और यदि कोई हो और ट्रिगर स्क्रिप्ट डालें। एक बार जब आप बल्क लोड पूरा कर लेते हैं तो आप अनुक्रमित को फिर से बना सकते हैं।
संदीप

जवाबों:


481

देखें एक डेटाबेस को पॉप्युलेट PostgreSQL के मैनुअल में, depesz उत्तम के रूप में हमेशा की तरह लेख विषय पर, और यह तो सवाल

(ध्यान दें कि यह उत्तर एक मौजूदा DB में थोक-लोडिंग डेटा के बारे में है या एक नया बनाने के लिए है। यदि आप रुचि रखते हैं DB उत्पादन के निष्पादन pg_restoreया psqlनिष्पादन को बहाल करते हैं, तो pg_dumpयह बहुत पहले से ही लागू नहीं होता है pg_dumpऔर pg_restoreजैसी चीजें बनाते हैं। ट्रिगर्स और इंडेक्स के बाद यह एक स्कीमा + डेटा रिस्टोर को पूरा करता है)

बहुत कुछ किया जाना है। आदर्श समाधान UNLOGGEDसूचकांक के बिना एक तालिका में आयात करना होगा , फिर इसे लॉग में बदलकर अनुक्रमित जोड़ना होगा। दुर्भाग्य से PostgreSQL 9.4 में UNLOGGEDलॉग से टेबल बदलने के लिए कोई समर्थन नहीं है । 9.5 ALTER TABLE ... SET LOGGEDआपको ऐसा करने की अनुमति देने के लिए जोड़ता है।

यदि आप थोक आयात के लिए अपने डेटाबेस को ऑफ़लाइन ले जा सकते हैं, तो उपयोग करें pg_bulkload

अन्यथा:

  • तालिका पर किसी भी ट्रिगर को अक्षम करें

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

  • यदि किसी एकल लेन-देन के भीतर आयात कर रहे हैं, तो विदेशी कुंजी बाधाओं को छोड़ना सुरक्षित है, आयात करें, और कमिट करने से पहले बाधाओं को फिर से बनाएं। ऐसा न करें यदि आयात कई लेन-देन में विभाजित है, तो आप अमान्य डेटा प्रस्तुत कर सकते हैं।

  • यदि संभव हो तो, एस के COPYबजाय का उपयोग करेंINSERT

  • यदि आप व्यावहारिक रूप से COPYबहु-मूल्यवान INSERTs का उपयोग करने पर विचार नहीं कर सकते हैं । आप पहले से ही ऐसा करते दिख रहे हैं। सूचीबद्ध करने का प्रयास न करेंVALUESहालांकि एक ही बार में बहुत सारे मूल्यों ; उन मूल्यों को एक-दो बार स्मृति में फिट होना होता है, इसलिए इसे प्रति कथन कुछ सौ तक रखें।

  • अपनी आवेषण को स्पष्ट लेन-देन में बैच दें, प्रति लेनदेन सैकड़ों या हजारों आवेषण करें। AFAIK की कोई व्यावहारिक सीमा नहीं है, लेकिन आपके इनपुट डेटा में प्रत्येक बैच की शुरुआत को चिह्नित करके आपको एक त्रुटि से उबरने देगा। फिर, आप पहले से ही ऐसा करते दिख रहे हैं।

  • Fsync () लागत को कम करने के लिए synchronous_commit=offएक विशाल और उपयोग करें commit_delay। यह बहुत मदद नहीं करेगा अगर आप अपने काम को बड़े लेनदेन में बदल चुके हैं, हालांकि।

  • INSERTया COPYकई कनेक्शनों से समानांतर में। आपके हार्डवेयर की डिस्क सबसिस्टम पर कितने निर्भर हैं; अंगूठे के एक नियम के रूप में, आप प्रत्यक्ष संलग्न भंडारण का उपयोग करते हुए भौतिक हार्ड ड्राइव के प्रति एक कनेक्शन चाहते हैं।

  • एक उच्च checkpoint_segmentsमूल्य सेट करें और सक्षम करें log_checkpoints। PostgreSQL लॉग को देखें और सुनिश्चित करें कि यह अक्सर होने वाली चौकियों के बारे में शिकायत नहीं कर रहा है।

  • यदि आप अपने पूरे PostgreSQL क्लस्टर (एक ही क्लस्टर पर अपने डेटाबेस और किसी भी अन्य) को नष्ट करने से बुरा नहीं करते हैं, तो विनाशकारी भ्रष्टाचार के लिए अगर आयात के दौरान सिस्टम क्रैश हो जाता है, तो आप Pg को रोक सकते हैं, सेट कर सकते हैं fsync=off, Pg शुरू कर सकते हैं, अपना आयात कर सकते हैं, तब (vitally) Pg को रोकें और fsync=onफिर से सेट करें। वाल कॉन्फ़िगरेशन देखें । यदि आपके पोस्टग्रेक्यूएल इंस्टाल पर किसी भी डेटाबेस में आपको पहले से ही कोई डेटा है, तो ऐसा न करें। यदि आप सेट fsync=offकरते हैं तो आप सेट भी कर सकते हैं full_page_writes=off; फिर से, डेटाबेस भ्रष्टाचार और डेटा हानि को रोकने के लिए अपने आयात के बाद इसे वापस चालू करना याद रखें। पीजी मैनुअल में गैर-टिकाऊ सेटिंग्स देखें ।

आपको अपने सिस्टम को देखते हुए भी देखना चाहिए:

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

  • यदि आप सीधे संलग्न भंडारण के लिए RAID 5 या RAID 6 का उपयोग कर रहे हैं, तो अभी रुकें। अपने डेटा का बैकअप लें, अपने RAID सरणी को RAID 10 में पुन: व्यवस्थित करें, और पुन: प्रयास करें। RAID 5/6 थोक लेखन प्रदर्शन के लिए निराशाजनक हैं - हालांकि एक अच्छा RAID नियंत्रक एक बड़े कैश के साथ मदद कर सकता है।

  • यदि आपके पास एक बड़ी बैटरी समर्थित राइट-बैक कैश के साथ हार्डवेयर RAID नियंत्रक का उपयोग करने का विकल्प है, तो यह वास्तव में बहुत सारे कमिट के साथ वर्कलोड के लिए लेखन प्रदर्शन में सुधार कर सकता है। यदि आप async कमेटी के साथ कम से कम उपयोग कर रहे हैं या यदि आप बल्क लोडिंग के दौरान कम बड़े लेनदेन कर रहे हैं तो यह उतना मदद नहीं करता है।

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

आप फास्ट टेस्ट के लिए ऑप्टिमाइज़ पोस्टग्रेक्यूएल में भी दिलचस्पी ले सकते हैं ।


1
क्या आप इस बात से सहमत होंगे कि अगर अच्छी गुणवत्ता वाली SSD का उपयोग किया जाता है, तो RAID 5/6 का जुर्माना कुछ हद तक कम हो जाता है? स्पष्ट रूप से अभी भी एक दंड है, लेकिन मुझे लगता है कि अंतर HDDs के साथ तुलना में बहुत कम दर्दनाक है।

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

क्या हम उन्हें अनुक्रमित करने के बजाय केवल अनुक्रमणिका को अक्षम कर सकते हैं, उदाहरण के लिए, सेटिंग indisvalid( postgresql.org/docs/8.3/static/catalog-pg-index.html ) को झूठा करने के लिए, फिर डेटा लोड करें और फिर अनुक्रमित करके ऑनलाइन लाएं REINDEX?
व्लादिस्लाव रास्ट्रुसनी

1
@ क्रेगिंगर मैंने RAID-5 बनाम RAID-10 का एसएसडी के साथ एक पर्क एच 730 पर परीक्षण किया है। RAID-5 वास्तव में तेज़ है। इसके अलावा यह ध्यान देने योग्य हो सकता है कि बड़े बाइटिया के साथ संयोजन में सम्मिलित / लेनदेन कॉपी की तुलना में अधिक तेज़ लगता है। कुल मिलाकर अच्छी सलाह है।
atlaste

2
किसी को भी किसी भी प्रमुख गति में सुधार के साथ देख रहा है UNLOGGED? एक त्वरित परीक्षण 10-20% सुधार जैसा कुछ दिखाता है।
सर्ग

15

COPY table TO ... WITH BINARYदस्तावेज़ के अनुसार उपयोग करें जो " पाठ और सीएसवी प्रारूपों की तुलना में कुछ अधिक तेज है।" ।" ऐसा तभी करें जब आपके पास सम्मिलित करने के लिए लाखों पंक्तियाँ हों, और यदि आप बाइनरी डेटा के साथ सहज हैं।

बाइनरी इनपुट के साथ psycopg2 का उपयोग करके पायथन में एक उदाहरण नुस्खा है


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

11

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

  1. Protocol=-1कनेक्शन स्ट्रिंग में निर्दिष्ट करके "लेन-देन" करने के लिए रोलबैक-ऑन-त्रुटियों को सेट करें । डिफ़ॉल्ट रूप से psqlodbc "स्टेटमेंट" स्तर का उपयोग करता है, जो एक संपूर्ण लेनदेन के बजाय प्रत्येक स्टेटमेंट के लिए एक SAVEPOINT बनाता है, आवेषण को धीमा बनाता है।
  2. UseServerSidePrepare=1कनेक्शन स्ट्रिंग में निर्दिष्ट करके सर्वर-साइड तैयार कथनों का उपयोग करें । इस विकल्प के बिना ग्राहक पूरे सम्मिलित विवरण को प्रत्येक पंक्ति के साथ डाला जाता है।
  3. उपयोग करने वाले प्रत्येक कथन पर ऑटो-कमिट अक्षम करें SQLSetConnectAttr(conn, SQL_ATTR_AUTOCOMMIT, reinterpret_cast<SQLPOINTER>(SQL_AUTOCOMMIT_OFF), 0);
  4. एक बार सभी पंक्तियों को सम्मिलित करने के बाद, लेन-देन का उपयोग करके प्रतिबद्ध करें SQLEndTran(SQL_HANDLE_DBC, conn, SQL_COMMIT);। लेन-देन को स्पष्ट रूप से खोलने की आवश्यकता नहीं है।

दुर्भाग्य से, psqlodbc अनपेड SQLBulkOperationsइन्सर्ट स्टेटमेंट की एक श्रृंखला जारी करके "इम्प्लीमेंट्स" करता है , ताकि सबसे तेज इन्सर्ट को प्राप्त करने के लिए उपरोक्त चरणों को मैन्युअल रूप से कोड करना पड़े।


A8=30000000कनेक्शन स्ट्रिंग में बड़े सॉकेट बफर आकार, आवेषण को गति देने के लिए भी उपयोग किया जाना चाहिए।
एंड्रस

9

मैंने आज उसी मुद्दे पर लगभग 6 घंटे बिताए। आवेषण एक 'नियमित' गति (3sec प्रति 100K से कम) पर 5MI (कुल 30MI से बाहर) पंक्तियों तक जाते हैं और फिर प्रदर्शन बहुत तेजी से डूबता है (सभी तरह से 1min प्रति 100K तक)।

मैं उन सभी चीजों को सूचीबद्ध नहीं करूंगा जो काम नहीं करते थे और सीधे मांस में कटौती करते थे।

मैंने लक्ष्य तालिका (जो एक GUID थी) पर एक प्राथमिक कुंजी को गिरा दिया और मेरी 30MI या पंक्तियाँ खुशी से अपने गंतव्य पर 100s से कम 3sec की निरंतर गति से प्रवाहित हुईं।


6

यदि आप UUIDs (जो वास्तव में आपका मामला नहीं है ) और @DSON उत्तर (मैं अभी तक टिप्पणी नहीं कर सकता) के साथ कॉलम्स सम्मिलित करने के लिए खुश हूं, तो gen_random_uuid () (PG 9.4 और pccrypto मॉड्यूल की आवश्यकता है) का उपयोग करने की सलाह दें (एक) बहुत) uuid_generate_v4 की तुलना में तेज़ ()

=# explain analyze select uuid_generate_v4(),* from generate_series(1,10000);
                                                        QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------
 Function Scan on generate_series  (cost=0.00..12.50 rows=1000 width=4) (actual time=11.674..10304.959 rows=10000 loops=1)
 Planning time: 0.157 ms
 Execution time: 13353.098 ms
(3 filas)

बनाम


=# explain analyze select gen_random_uuid(),* from generate_series(1,10000);
                                                        QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------
 Function Scan on generate_series  (cost=0.00..12.50 rows=1000 width=4) (actual time=252.274..418.137 rows=10000 loops=1)
 Planning time: 0.064 ms
 Execution time: 503.818 ms
(3 filas)

इसके अलावा, इसे करने का सुझाव दिया गया आधिकारिक तरीका है

ध्यान दें

यदि आपको केवल बेतरतीब ढंग से उत्पन्न (संस्करण 4) यूयूआईडी की आवश्यकता है, तो इसके बजाय pgcrypto मॉड्यूल से gen_random_uuid () फ़ंक्शन का उपयोग करने पर विचार करें।

यह 3.7M पंक्तियों के लिए ~ 2 घंटे से ~ 10 मिनट तक सम्मिलित समय छोड़ देता है।


1

यदि आपके लिए कोई विकल्प है, तो इष्टतम प्रविष्टि प्रदर्शन इंडेक्स को अक्षम करता है। इसके अलावा, बेहतर हार्डवेयर (डिस्क, मेमोरी) भी सहायक है


-1

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

db, _ := sql.open() 
db.SetMaxOpenConns(SOME CONFIG INTEGER NUMBER) 
var wg sync.WaitGroup
for _, query := range queries {
    wg.Add(1)
    go func(msg string) {
        defer wg.Done()
        _, err := db.Exec(msg)
        if err != nil {
            fmt.Println(err)
        }
    }(query)
}
wg.Wait()

मेरे प्रोजेक्ट के लिए लोडिंग की गति बहुत तेज है। इस कोड स्निपेट ने सिर्फ एक विचार दिया कि यह कैसे काम करता है। पाठकों को इसे आसानी से संशोधित करने में सक्षम होना चाहिए।


खैर, आप कह सकते हैं कि। लेकिन यह मेरे मामले के लिए लाखों पंक्तियों के लिए चलने के समय को कुछ घंटों से लेकर कई मिनटों तक कम कर देता है। :)
पैट्रिक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.