PostgreSQL में बहुत धीमी, वर्कअराउंड?


30

मेरे पास PostgreSQL 9.2 पर एक डेटाबेस है जिसमें लगभग 70 तालिकाओं के साथ एक मुख्य स्कीमा है और प्रत्येक 30-तालिकाओं के समान रूप से संरचित प्रति-ग्राहक स्कीमाओं की एक चर संख्या है। क्लाइंट स्कीमा में मुख्य स्कीमा को संदर्भित करने वाली विदेशी कुंजियाँ होती हैं, न कि दूसरे तरीके से।

मैंने बस पिछले संस्करण से लिए गए कुछ वास्तविक डेटा के साथ डेटाबेस को भरना शुरू किया। डीबी लगभग 1.5 जीबी तक पहुंच गया था (यह हफ्तों के भीतर कई 10 जीबी तक बढ़ने की उम्मीद है) जब मुझे मुख्य स्कीमा में एक बहुत ही केंद्रीय तालिका में एक बल्क डिलीट करना था। सभी संबंधित विदेशी कुंजियों को DELETE CASCADE पर चिह्नित किया गया है।

यह कोई आश्चर्य की बात नहीं थी कि इसमें लंबा समय लगेगा, लेकिन 12 घंटे के बाद यह स्पष्ट हो गया कि मैं शुरू करने से बेहतर था, डीबी को छोड़ कर और फिर से प्रवास शुरू किया। लेकिन क्या होगा अगर मुझे इस ऑपरेशन को बाद में दोहराने की जरूरत है जब डीबी जीवित है और बहुत बड़ा है? क्या वैकल्पिक, तेज तरीके हैं?

क्या यह बहुत तेजी से होगा यदि मैंने एक स्क्रिप्ट लिखी है जो कि निर्भर तालिकाओं को ब्राउज़ करेगी, केंद्रीय तालिका से सबसे दूर मेज पर शुरू करना, तालिका द्वारा आश्रित पंक्तियों की तालिका को हटाना?

एक महत्वपूर्ण विवरण यह है कि कुछ तालिकाओं पर ट्रिगर होते हैं।


4
5 साल बाद, मैं स्वीकृत उत्तर बदल रहा हूं। धीरे-धीरे DELETE लगभग हमेशा विदेशी कुंजी पर लापता अनुक्रमित के कारण होते हैं जो प्रत्यक्ष या अप्रत्यक्ष रूप से तालिका से हटाए जाने का संदर्भ देते हैं। DELETE कथनों पर आग लगाने वाले ट्रिगर चीजों को बहुत धीमा कर सकते हैं, हालांकि समाधान लगभग हमेशा उन्हें तेजी से चलाने के लिए होता है (जैसे लापता अनुक्रमणिका जोड़कर) और लगभग सभी ट्रिगर को अक्षम करने के लिए कभी नहीं।
जद।

जवाबों:


30

मुझे भी ऐसी ही समस्या का समाधान करना पड़ा था। जैसा कि यह पता चला है, उन ON DELETE CASCADEट्रिगर्स चीजों को थोड़ा धीमा कर रहे थे, क्योंकि उन कैस्केड विलोपन भयानक रूप से धीमा थे।

मैंने संदर्भित तालिकाओं पर विदेशी प्रमुख क्षेत्रों पर अनुक्रमित बनाकर समस्या का हल किया, और मैं कुछ सेकंड के विलोपन के लिए घंटों का एक गुच्छा लेने से चला गया।


वाह, इससे मुझे कुछ ही मिनटों में 8M रिकॉर्ड हटाने में मदद मिली। लेकिन जो मुझे समझ में नहीं आता है वह यह है कि मेरी तालिका में केवल अन्य तालिकाओं के संदर्भ हैं, कोई अन्य तालिका मेरी तालिका के संदर्भ नहीं रखती है। तो यहाँ वास्तव में क्या प्रभाव है? (मैं उपयोग नहीं कर रहा हूं ON DELETE CASCADE)
msrd0

2
यह मेरे लिए भी हल कर दिया। यह कोशिश करने वाले किसी भी व्यक्ति के लिए, आप EXPLAIN (ANALYZE, BUFFERS)एक पंक्ति हटाए जाने पर एक क्वेरी कर सकते हैं और यह आपको दिखाना चाहिए कि विदेशी कुंजी बाधाओं ने सबसे लंबा समय लिया (कम से कम यह मेरे लिए किया था)।
जस्टिन वर्कमैन

समान, को कैस्केड 600k पंक्तियों पर हटाना पड़ा और शुरुआत में यह 100% CPU उपयोग के साथ 2-10 प्रति ऑपरेशन के बीच ले रहा था। अब उन सभी को 80% CPU उपयोग के साथ हटाने में केवल कुछ ही मिनट लगे।
फिलोबोटोऑक्ट

यह ध्यान रखना महत्वपूर्ण है कि यदि आपके पास कहीं भी एक विदेशी संदर्भ है, तो स्रोत कॉलम में वास्तविक सूचकांक होना चाहिए या प्रदर्शन को नुकसान होगा। मुझे यकीन नहीं है कि यदि PRIMARYसूचकांक पर्याप्त है लेकिन UNIQUEसूचकांक निश्चित रूप से इस उद्देश्य के लिए पर्याप्त नहीं है।
मिको रानाल्टेन ने

26

आपके पास कुछ विकल्प हैं। सबसे अच्छा विकल्प बैच डिलीट चलाना है ताकि ट्रिगर हिट न हो। हटाने से पहले ट्रिगर अक्षम करें, फिर उन्हें पुन: सक्षम करें। यह आपको बहुत बड़ी मात्रा में समय बचाता है। उदाहरण के लिए:

ALTER TABLE tablename DISABLE TRIGGER ALL; 
DELETE ...; 
ALTER TABLE tablename ENABLE TRIGGER ALL;

यहां एक प्रमुख कुंजी यह है कि आप उप-वर्ग की गहराई को कम करना चाहते हैं। इस मामले में आप प्रासंगिक जानकारी संग्रहीत करने के लिए अस्थायी तालिकाओं को स्थापित करना चाह सकते हैं ताकि आप अपने हटाए जाने पर गहरी अधीनताओं से बच सकें।


मेरे मामले में, मैंने बिस्तर पर जाने से पहले DELETE FROM कमांड शुरू किया और यह तब भी नहीं हुआ जब मैं अगले दिन अपने कंप्यूटर पर लौटा। पूरे समय एक कोर पर 100% सीपीयू का उपयोग होता है। ट्रिगर को अक्षम करने और फिर से प्रयास करने के बाद 200k रिकॉर्ड को हटाने में 3 सेकंड का समय लगा। धन्यवाद!
निक वुडहम्स

13

समस्या को हल करने का सबसे आसान तरीका PostgreSQL से विस्तृत समय की क्वेरी करना है EXPLAIN:। इसके लिए आपको कम से कम एक ऐसी क्वेरी खोजने की आवश्यकता है जो पूर्ण हो लेकिन अपेक्षा से अधिक समय लेती हो। मान लीजिए कि यह रेखा दिखती है

delete from mydata where id='897b4dde-6a0d-4159-91e6-88e84519e6b6';

वास्तव में उस कमांड को चलाने के बजाय आप कर सकते हैं

begin;
explain (analyze,buffers,timing) delete from mydata where id='897b4dde-6a0d-4159-91e6-88e84519e6b6';
rollback;

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

...
Trigger for constraint XYZ123: time=12311.292 calls=1
...

timeएमएस (मिलीसेकंड) में है तो यह contraint जाँच 12.3 सेकंड के बारे में ले लिया। आपको INDEXआवश्यक स्तंभों पर एक नया जोड़ना होगा ताकि इस ट्रिगर को प्रभावी ढंग से गणना की जा सके। विदेशी कुंजी संदर्भों के लिए, किसी अन्य तालिका के संदर्भ वाले स्तंभ को अनुक्रमित किया जाना चाहिए (अर्थात, स्रोत स्तंभ, लक्ष्य स्तंभ नहीं)। PostgreSQL स्वचालित रूप से आपके लिए ऐसे इंडेक्स नहीं बनाता DELETEहै और केवल सामान्य क्वेरी है जहां आपको वास्तव में उस इंडेक्स की आवश्यकता होती है। परिणामस्वरूप, आपके पास वर्षों का डेटा जमा हो सकता है जब तक कि आप उस मामले को नहीं मारते हैं जहां DELETEसूचकांक धीमा होने के कारण बहुत धीमा है।

एक बार जब आप उस बाधा का प्रदर्शन तय कर लेते हैं (या कोई अन्य चीज जो लंबे समय से अधिक समय लेती है), begin/ में कमांड दोहराएंrollback ब्लॉक ताकि आप नए निष्पादन समय की तुलना पिछले कर सकें। तब तक जारी रखें जब तक आप सिंगल लाइन डिलीट रिस्पांस टाइम से खुश न हों (मुझे अलग-अलग इंडेक्स जोड़कर 25.6 सेकंड से 15 एमएस तक जाने के लिए एक क्वेरी मिली)। फिर आप बिना किसी हैक के अपना पूरा डिलीट करने के लिए आगे बढ़ सकते हैं।

(ध्यान दें कि EXPLAINएक क्वेरी की आवश्यकता है जो सफलतापूर्वक पूरी हो सकती है। मेरे पास एक बार एक समस्या थी जहां PostgreSQL को यह पता लगाने में लंबा समय लगा कि एक डिलीट एक विदेशी कुंजी बाधा का उल्लंघन करने वाला था और उस स्थिति में EXPLAINइसका उपयोग नहीं किया जा सकता क्योंकि यह विफल होने के लिए समय का उत्सर्जन नहीं करेगा। प्रश्न। मुझे इस तरह के मामले में प्रदर्शन के मुद्दों पर बहस करने का कोई आसान तरीका नहीं पता है।)


8

ट्रिगर अक्षम करना DB अखंडता के लिए खतरा हो सकता है और इसकी सिफारिश नहीं की जा सकती है; हालाँकि, यदि आप सुनिश्चित हैं कि आपका ऑपरेशन अड़चन-विफलता-सबूत है, तो आप निम्नलिखित के साथ ट्रिगर को अक्षम कर सकते हैं:SET session_replication_role = replica;

DELETEयहां भागो ।

ट्रिगर बहाल करने के लिए, चलाएं: SET session_replication_role = DEFAULT;

स्रोत यहाँ


0

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

CREATE TABLE tablea (
    tablea_uid integer
);

CREATE TABLE tableb (
    tableb_uid integer,
    tablea_rid integer REFERENCES tablea(tablea_uid)
);

CREATE TABLE tablec (
    tablec_uid integer,
    tableb_rid integer REFERENCES tableb(tableb_uid)
);

इस स्थिति में तालिका में डेटा को हटा दें और फिर तालिका को सारणीबद्ध करें

CREATE OR REPLACE FUNCTION delete_in_order()
 RETURNS void AS $$

    DELETE FROM tablec;
    DELETE FROM tableb;
    DELETE FROM tablea;

$$ LANGUAGE SQL;
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.