तालिका में अशक्त स्तंभ जोड़ने में 10 मिनट से अधिक का समय लगता है


11

मुझे एक टेबल पर एक नया कॉलम जोड़ने की समस्या है।
मैंने इसे कई बार चलाने की कोशिश की, लेकिन 10 मिनट से अधिक चलने के बाद, मैंने लॉक समय के कारण क्वेरी को रद्द करने का निर्णय लिया।

ALTER TABLE mytable ADD mycolumn VARCHAR(50);

उपयोगी जानकारी:

  • PostgreSQL संस्करण: 9.1
  • पंक्तियों की संख्या: ~ 250K
  • कॉलम की संख्या: 38
  • अशक्त स्तंभों की संख्या: 32
  • बाधाओं की संख्या: 5 (1 PK, 3 FK, 1 UNIQUE)
  • अनुक्रमित की संख्या: 1
  • ओएस प्रकार: डेबियन निचोड़ 64

मुझे इस बात की रोचक जानकारी मिली कि जिस तरह से PostgreSQL nullable कॉलम (HeapTupleHeader के माध्यम से) का प्रबंधन करता है।

मेरा पहला अनुमान है कि क्योंकि इस तालिका में पहले से ही 8-बिट्स के साथ 32 MAXALIGNअशक्त स्तंभ हैं , HeapTupleHeader 4 बाइट्स लंबाई है (सत्यापित नहीं है, और मुझे नहीं पता कि यह कैसे करना है)।

इसलिए एक नया अशक्त स्तंभ जोड़ने के लिए एक नया 8-बिट्स जोड़ने के लिए हर पंक्ति पर HeapTupleHeader के अपडेट की आवश्यकता MAXALIGNहो सकती है, जिससे प्रदर्शन समस्याएँ हो सकती हैं।

इसलिए मैंने एक अशक्त स्तंभों (जो वास्तव में वास्तव में अशक्त नहीं है) को बदलने की कोशिश की, ताकि मेरे अनुमान सच हो सकें, यह जांचने के लिए 31 अशक्त स्तंभों की संख्या घट जाए।

ALTER TABLE mytable ALTER myothercolumn SET NOT NULL;

दुर्भाग्य से, इस परिवर्तन में बहुत लंबा समय लगता है, 5 मिनट से अधिक, इसलिए मैंने इसे समाप्त कर दिया।

क्या आपको इस बात का अंदाजा है कि इस प्रदर्शन की लागत क्या हो सकती है?


1
ठीक है, मैं आपको इसका हिस्सा बता सकता हूं: एक स्तंभ प्रकार को किसी अन्य प्रकार में बदलना जो कि द्विआधारी संगत नहीं है वास्तव में एक नया स्तंभ बनाता है, डेटा की प्रतिलिपि बनाता है, और पुराने कॉलम को गिरा दिया के रूप में सेट करता है। हालांकि, SET NOT NULLप्रकार में परिवर्तन नहीं करता है, यह सिर्फ एक बाधा कहते हैं - लेकिन बाधा किया जाना चाहिए जाँच की मेज के खिलाफ है, और है कि एक पूर्ण तालिका स्कैन की आवश्यकता है। 9.4 कमजोर ताले लेकर इनमें से कुछ मामलों में सुधार होता है, लेकिन यह अभी भी बहुत भारी है।
क्रेग रिंगर

1
यह संदेह करने से पहले कि यह धीरे-धीरे प्रदर्शन कर रहा है, आपको यह सुनिश्चित करने की आवश्यकता है कि ALTER TABLE सिर्फ लॉक का इंतजार नहीं कर रही है। यदि आपने जाँच कर ली है तो इसे प्रश्न में उल्लेख करें।
डैनियल वेटरे

धन्यवाद क्रेग और डैनियल। जब मैं परिवर्तन कमांड चलाता हूं, तो यह "सही" प्रतीक्षा के साथ pg_stat_activity में प्रकट होता है, मुझे लगता है कि इसका मतलब है कि यह एक लॉक की प्रतीक्षा करता है? यह जाँच के लिए अच्छा तरीका है? वैसे, इस परिवर्तन को चलाने से पहले, सब कुछ ठीक हो जाता है, लेकिन शुरू होने के कुछ सेकंड बाद, तालों की संख्या बढ़ती है

बेहतर दृश्य के लिए wiki.postgresql.org/wiki/Lock_d dependency_information पर क्वेरी आज़माएं । या तो आपके पास लेन-देन लेन-देन है जो प्रतिबद्ध करना भूल जाता है, या इस तालिका के साथ भारी गतिविधि जो इसे हमेशा व्यस्त रखती है।
डेनियल वेट्रे

Dba.SE में एक बेहतर फिट हो सकता है।
एरविन ब्रैंडस्टैटर

जवाबों:


8

यहाँ गलतफहमी के कुछ जोड़े हैं:

अशक्त बिटमैप है नहीं ढेर टपल हैडर का हिस्सा है। प्रति प्रलेखन:

एक निश्चित आकार का हेडर है (अधिकांश मशीनों पर 23 बाइट्स पर कब्जा कर रहा है), इसके बाद एक वैकल्पिक नल बिटमैप ...

आपके 32 अशक्त स्तंभ दो कारणों से शुभ हैं:

  • अशक्त बिटमैप प्रति पंक्ति में जोड़ा जाता है , और केवल तभी जब पंक्ति में कम से कम एक वास्तविक NULLमूल्य हो। अशक्त स्तंभों का कोई प्रत्यक्ष प्रभाव नहीं होता है, केवल वास्तविक NULLमूल्य होते हैं। यदि नल बिटमैप आवंटित किया गया है, तो यह हमेशा पूरी तरह से आवंटित किया जाता है (सभी या कुछ भी नहीं)। नल बिटमैप का वास्तविक आकार 1 बिट प्रति स्तंभ है, अगले बाइट तक गोल हैवर्तमान करंट सॉप कोड:

    #define BITMAPLEN(NATTS) (((int)(NATTS) + 7) / 8)
  • नल बिटमैप ढेर टपल हेडर के बाद आवंटित किया गया है और उसके बाद एक वैकल्पिक OID और फिर पंक्ति डेटा। OID या पंक्ति डेटा की शुरुआत t_hoffहेडर में इंगित की गई है। प्रति टिप्पणी स्रोत कोड :

    ध्यान दें कि t_hoff अधिकतम MAXALIGN का होना चाहिए।

  • ढेर टपल हेडर के बाद एक मुफ्त बाइट है, जिसमें 23 बाइट्स हैं। तो 8 कॉलम तक की पंक्तियों के लिए नल बिटमैप प्रभावी रूप से बिना किसी अतिरिक्त लागत के आता है। तालिका में 9 वें कॉलम के साथ, एक और 64 कॉलम के लिए प्रदान करने के लिए एक t_hoffऔर MAXALIGN(आमतौर पर 8) बाइट्स उन्नत है । तो अगली सीमा 72 स्तंभों पर होगी ।

PostgreSQL डेटाबेस क्लस्टर (incl। MAXALIGN) की नियंत्रण जानकारी प्रदर्शित करने के लिए, डेबियन मशीन पर Postgres 9.3 की एक विशिष्ट स्थापना के लिए उदाहरण:

    sudo /usr/lib/postgresql/9.3/bin/pg_controldata /var/lib/postgresql/9.3/main

मैंने आपके द्वारा उद्धृत संबंधित उत्तर में निर्देश अपडेट किए ।

यह सब एक तरफ, भले ही आपका ALTER TABLEबयान एक पूरी तालिका को फिर से लिखना (जो शायद ऐसा करता है, एक डेटा प्रकार बदल रहा है), 250K वास्तव में इतना नहीं है और किसी भी आधे रास्ते सभ्य मशीन पर सेकंड का मामला होगा (जब तक कि पंक्तियां असामान्य रूप से बड़ी न हों) । 10 मिनट या अधिक पूरी तरह से अलग समस्या का संकेत देते हैं। आपका कथन तालिका पर ताला लगने की प्रतीक्षा कर रहा है, सबसे अधिक संभावना है।

pg_stat_activityअधिक खुले लेन-देन में प्रविष्टियों की बढ़ती संख्या - तालिका पर समवर्ती पहुंच को इंगित करता है (सबसे अधिक संभावना है) जिसे ऑपरेशन खत्म होने का इंतजार करना पड़ता है।

अंधेरे में कुछ शॉट

संभावित टेबल ब्लोट के लिए जाँच करें, एक सौम्य VACUUM mytableया अधिक आक्रामक प्रयास करें VACUUM FULL mytable- जो समान समसामयिक मुद्दों का सामना कर सकता है, क्योंकि यह फ़ॉर्म एक अनन्य लॉक का भी अधिग्रहण करता है। आप इसके बजाय pg_repack आज़मा सकते हैं ...

मैं अनुक्रमणिका, ट्रिगर, विदेशी कुंजी या अन्य बाधाओं के साथ संभावित मुद्दों का निरीक्षण करके शुरू करूंगा, विशेष रूप से उन स्तंभों को शामिल करना। विशेष रूप से एक दूषित सूचकांक शामिल हो सकता है? कोशिश करें REINDEX TABLE mytable;या DROPउनमें से सभी और ALTER TABLE उसी लेनदेन के बाद उन्हें फिर से जोड़ें ।

रात में या जब भी ज्यादा लोड न हो, कमांड चलाने की कोशिश करें।

एक जानवर-बल विधि सर्वर तक पहुंच को रोकने के लिए होगी, फिर पुन: प्रयास करें:

इसे नीचे पिन करने में सक्षम होने के बिना, वर्तमान संस्करण में अपग्रेड करना या आगामी 9.4 विशेष रूप से मदद कर सकता है। बड़ी तालिकाओं और लॉकिंग विवरण के लिए कई सुधार हुए हैं। लेकिन अगर आपके DB में कुछ टूट गया है, तो आपको संभवतः यह पता लगाना चाहिए कि पहले बाहर।


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

स्पष्टीकरण के लिए धन्यवाद इरविन। मुझे लगता है कि आप सही हैं, यह एक ताला समस्या प्रतीत होती है। जब मैं pg_stat_activity की जांच करता हूं, तो मैं देख सकता हूं कि मेरे ALTER में "प्रतीक्षा" सत्य है। मैं यह पता नहीं लगा सकता कि एलेटर टेबल पर ताला क्यों नहीं लगा सकता है, यहां तक ​​कि तब भी जब मुझे कोई क्वेरी नहीं मिल रही है, ऐसा लगता है कि यह नहीं मिल सकता है। लेकिन जैसे ही मेरा अलर्ट चलना शुरू होता है, अन्य सभी प्रश्न समाप्त होने की प्रतीक्षा कर रहे हैं। इसलिए, गतिविधि यह बताती है कि ALTER अन्य सभी प्रश्नों को लॉक करता है, लेकिन यह भी इंगित करता है कि ALTER को लॉक नहीं मिला। मुझे लगता है कि कुछ ऐसा है जिसे मैं अच्छी तरह से नहीं समझता!

@MatthieuVerrecchia: क्या आपने रिचर्ड द्वारा सुझाए गए परीक्षण की कोशिश की?
इरविन ब्रांडस्टैटर

1
मैंने अभी अपनी तालिका एक नए (pg_dump -> pg_sql के साथ) पर क्लोन की है। नया कॉलम 50ms में सही ढंग से जोड़ा गया है, जो लॉक की समस्या की पुष्टि करता है। वैसे, अभी भी समझ में नहीं आ रहा है कि ALTER वास्तव में मानक db गतिविधि के साथ लॉक क्यों नहीं कर सकता है।

1
@ErwinBrandstetter मैंने आपके सुझावों का पालन किया है और VACUUM की कोशिश की, फिर एक REINDEX। REINDEX भी ब्लॉक कर रहा था, क्योंकि यह लॉक हासिल करने में भी असमर्थ था .. कुछ जांच के बाद, समस्या हम से बहुत आसान थी .. आप एक सप्ताह शेष थे <IDLE> एक खुले लेन-देन के साथ समस्या हल हो गई है, धन्यवाद सब कुछ के लिए, informations बहुत उपयोगी थे।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.