पोस्टग्रैड को UPDATE को 39 घंटे क्यों लगे?


17

मेरे पास ~ 2.1 मिलियन पंक्तियों के साथ एक पोस्टग्रैज टेबल है। मैंने इस पर नीचे का अद्यतन चलाया:

WITH stops AS (
    SELECT id,
           rank() OVER (ORDER BY offense_timestamp,
                     defendant_dl,
                     offense_street_number,
                     offense_street_name) AS stop
    FROM   consistent.master
    WHERE  citing_jurisdiction=1
)

UPDATE consistent.master
SET arrest_id=stops.stop
FROM stops
WHERE master.id = stops.id;

इस क्वेरी को चलने में 39 घंटे लगे। मैं इसे एक 4 (भौतिक) कोर i7 Q720 लैपटॉप प्रोसेसर पर चला रहा हूं, बहुत सारे रैम, और कुछ नहीं, अधिकांश समय चल रहा है। कोई HDD स्पेस की कमी नहीं। तालिका को हाल ही में वैक्यूम किया गया था, विश्लेषण किया गया था और फिर से जोड़ा गया था।

पूरे समय क्वेरी चल रही थी, कम से कम प्रारंभिक WITHपूरा होने के बाद , सीपीयू का उपयोग आमतौर पर कम था, और एचडीडी 100% उपयोग में था। एचडीडी को इतनी मेहनत से इस्तेमाल किया जा रहा था कि कोई भी अन्य ऐप सामान्य की तुलना में बहुत धीरे-धीरे चलता था।

लैपटॉप की पावर सेटिंग उच्च प्रदर्शन (विंडोज 7 x64) पर थी।

यहां देखें:

Update on master  (cost=822243.22..1021456.89 rows=2060910 width=312)
  CTE stops
    ->  WindowAgg  (cost=529826.95..581349.70 rows=2060910 width=33)
          ->  Sort  (cost=529826.95..534979.23 rows=2060910 width=33)
                Sort Key: consistent.master.offense_timestamp, consistent.master.defendant_dl, consistent.master.offense_street_number, consistent.master.offense_street_name
                ->  Seq Scan on master  (cost=0.00..144630.06 rows=2060910 width=33)
                      Filter: (citing_jurisdiction = 1)
  ->  Hash Join  (cost=240893.51..440107.19 rows=2060910 width=312)
        Hash Cond: (stops.id = consistent.master.id)
        ->  CTE Scan on stops  (cost=0.00..41218.20 rows=2060910 width=48)
        ->  Hash  (cost=139413.45..139413.45 rows=2086645 width=268)
              ->  Seq Scan on master  (cost=0.00..139413.45 rows=2086645 width=268)

citing_jurisdiction=1केवल हजारों पंक्तियों में से कुछ को छोड़कर। यहां तक ​​कि उस WHEREक्लॉज के साथ , मैं अभी भी 2 मिलियन से अधिक पंक्तियों पर काम कर रहा हूं।

हार्ड ड्राइव TrueCrypt 7.1a के साथ पूरे ड्राइव-एन्क्रिप्टेड है। यह चीज़ों को थोड़ा धीमा करता है, लेकिन ऐसा करने के लिए पर्याप्त नहीं है कि कई घंटे लगें।

WITHहिस्सा केवल 3 मिनट चलाने के बारे में लेता है।

इस arrest_idक्षेत्र में विदेशी कुंजी के लिए कोई सूचकांक नहीं था। इस टेबल पर 8 इंडेक्स और 2 विदेशी चाबियां हैं। क्वेरी में अन्य सभी फ़ील्ड अनुक्रमित हैं।

arrest_idक्षेत्र को छोड़कर कोई कमी नहीं हुई NOT NULL

तालिका में कुल 32 कॉलम हैं।

arrest_idप्रकार का वर्ण भिन्न होता है (20) । मुझे एहसास है कि rank()एक संख्यात्मक मूल्य का उत्पादन होता है, लेकिन मुझे चरित्र भिन्न (20) का उपयोग करना होगा क्योंकि मेरे पास अन्य पंक्तियाँ हैं citing_jurisdiction<>1जो इस क्षेत्र में गैर-संख्यात्मक डेटा का उपयोग करती हैं।

arrest_idक्षेत्र के साथ सभी पंक्तियों के लिए खाली था citing_jurisdiction=1

यह एक व्यक्तिगत, उच्च अंत (1 वर्ष पहले) लैपटॉप है। मैं केवल उपयोगकर्ता हूँ। कोई अन्य प्रश्न या संचालन नहीं चल रहा था। ताला लगने की संभावना कम लगती है।

इस तालिका में या डेटाबेस में कहीं भी कोई ट्रिगर नहीं हैं।

इस डेटाबेस के अन्य संचालन कभी भी समय की एक विषम राशि नहीं लेते हैं। उचित अनुक्रमण के साथ, SELECTप्रश्न आमतौर पर काफी तेज होते हैं।


वे Seq Scanथोड़े डरावने हैं ...
रोज़गारपैक

जवाबों:


18

मैंने हाल ही में 3.5 मिलियन पंक्तियों की तालिका के साथ कुछ ऐसा ही किया था। मेरा अपडेट कभी खत्म नहीं होगा। बहुत सारे प्रयोग और हताशा के बाद, आखिरकार मुझे दोषी पाया गया। यह अद्यतन की जा रही मेज पर अनुक्रमित होना निकला।

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

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


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

1
धन्यवाद! आशा है कि यह दूसरों की मदद करता है। यह मुझे कुछ सरल प्रतीत होता है के लिए सिर दर्द के घंटे बचा लिया है।
जेसी अवेना

5
@ArenCambre - एक कारण है: PostgreSQL पूरी पंक्ति को एक अलग स्थान पर कॉपी करता है और हटाए गए के रूप में पुराने संस्करण को चिह्नित करता है। यह है कि PostgreSQL मल्टी-वर्ज़न कंसीलर कंट्रोल (MVCC) को कैसे लागू करता है।
पायोटर फाइंडसेन

मेरा सवाल है ... यह अपराधी क्यों है? यह भी देखें stackoverflow.com/a/35660593/32453
rogerdpack

15

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

TrueCrypt लिखने के लिए "थोड़ी" से अधिक चीजों को धीमा कर देता है। रीडर्स यथोचित तेज़ होंगे, लेकिन लिखते हैं RAID 5 तेजी से देखो। ट्रू-क्रिप्ट वॉल्यूम पर डीबी चलाने से राइट्स, खासकर रैंडम राइट्स के लिए अत्याचार होगा।

इस मामले में, मुझे लगता है कि आप क्वेरी को अनुकूलित करने की कोशिश में अपना समय बर्बाद कर रहे होंगे। आप वैसे भी अधिकांश पंक्तियों को फिर से लिख रहे हैं, और यह आपकी भयानक लेखन स्थिति के साथ धीमा होने जा रहा है। मैं क्या सुझाऊंगा:

BEGIN;
SELECT ... INTO TEMPORARY TABLE master_tmp ;
TRUNCATE TABLE consistent.master;
-- Now DROP all constraints on consistent.master, then:
INSERT INTO consistent.master SELECT * FROM master_tmp;
-- ... and re-create any constraints.

मुझे संदेह है कि केवल बाधाओं को छोड़ने और फिर से बनाने से ज्यादा तेजी से होगा, क्योंकि एक अद्यतन में काफी यादृच्छिक लेखन पैटर्न होंगे जो आपके भंडारण को मार देंगे । दो बल्क इंसट्रक्ट्स, एक अनलॉग्ड टेबल में और एक बिना किसी बाधा के वाल-लॉग टेबल में, संभवत: तेज होगा।

यदि आपके पास अप-टू-डेट बैकअप हैं और बैकअप से अपने डेटाबेस को पुनर्स्थापित करने में कोई आपत्ति नहीं है, तो आप पोस्टग्रेएसक्यू को fsync=offपैरामीटर के साथ और इस थोक ऑपरेशन के लिए full_page_writes=off अस्थायी रूप से फिर से शुरू कर सकते हैं । पावर लॉस या OS क्रैश जैसी कोई भी अप्रत्याशित समस्या आपके डेटाबेस को अप्राप्य करते समय छोड़ देगी fsync=off

"नहीं लॉगिंग" के बराबर POSTGreSQL अनलॉगेड तालिकाओं का उपयोग करना है। यदि गंदे होने पर DB असमतलता से नीचे गिरता है, तो ये अनियोजित तालिकाओं को काट दिया जाता है। अनलॉग्ड तालिकाओं का उपयोग करने से कम से कम आपके लेखन भार को आधा कर दिया जाएगा और उनकी संख्या कम कर दी जाएगी, इसलिए वे बहुत तेजी से हो सकते हैं ।

ओरेकल की तरह, एक इंडेक्स को गिराने के लिए एक अच्छा विचार हो सकता है फिर एक बड़े बैच अपडेट के बाद इसे फिर से बनाएं। PostgreSQL का प्लानर काम नहीं कर सकता है कि एक बड़ा अपडेट हो रहा है, इंडेक्स अपडेट को रोकें, फिर अंत में इंडेक्स को फिर से बनाएं; यहां तक ​​कि अगर यह कर सकता है, तो यह पता लगाना बहुत मुश्किल होगा कि किस बिंदु पर यह करने लायक था, खासकर अग्रिम में।


यह उत्तर बड़ी मात्रा में लिखने और एन्क्रिप्शन प्लस धीमे लैपटॉप ड्राइव की भयानक पूर्णता पर है। मैं यह भी नोट करूंगा कि 8 इंडेक्स की उपस्थिति कई अतिरिक्त राइट्स का निर्माण करती है और हॉट -ब्लॉक पंक्ति अपडेट की प्रयोज्यता को हरा देती है , इसलिए इंडेक्स छोड़ने और टेबल पर एक कम भराव का उपयोग करने से एक टन की पंक्ति माइग्रेशन को रोका जा सकता है
debhit

1
एक फिल्फैक्टर के साथ HOTs के अवसरों को बढ़ाने पर अच्छी कॉल - हालांकि ट्रू-क्रिप्ट मजबूरन ब्लॉक-रीड-राइट साइकल को विशाल ब्लॉकों में रखने के साथ, मुझे यकीन नहीं है कि यह बहुत मदद करेगा; पंक्ति माइग्रेशन और भी तेज़ हो सकता है क्योंकि तालिका का बढ़ना कम से कम लेखन के रैखिक-ईश ब्लॉक कर रहा है।
क्रेग रिंगर

2.5 साल बाद मैं भी कुछ ऐसा ही कर रहा हूं, लेकिन एक बड़ी मेज पर। बस यह सुनिश्चित करने के लिए कि क्या सभी इंडेक्स को गिराना एक अच्छा विचार है, भले ही मैं जो सिंगल कॉलम अपडेट कर रहा हूं उसे इंडेक्स नहीं किया गया है?
एरेन कैंब्रिज

1
@ArenCambre उस मामले में ... ठीक है, यह जटिल है। यदि आपका अधिकांश अपडेट इसके लिए योग्य है, HOTतो सूचकांक को जगह में छोड़ना बेहतर है। यदि नहीं, तो आप संभवतः ड्रॉप और फिर से बनाना चाहेंगे। स्तंभ को अनुक्रमित नहीं किया गया है, लेकिन एक HOT अपडेट करने में सक्षम होने के लिए भी उसी पृष्ठ पर मुक्त स्थान होना चाहिए, इसलिए यह थोड़ा निर्भर करता है कि तालिका में कितना मृत स्थान है। अगर यह सबसे अधिक है, तो मैं कहता हूँ कि मैं सभी अनुक्रमों को छोड़ दूंगा। यदि यह बहुत अद्यतन किया जाता है तो इसमें छेद हो सकते हैं और आप ठीक हो सकते हैं। जैसे उपकरण pageinspectऔर pg_freespacemapयह निर्धारित करने में मदद कर सकते हैं।
क्रेग रिंगर

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

2

कोई व्यक्ति पोस्टग्रेज के लिए बेहतर उत्तर देगा, लेकिन यहां ओरेकल के दृष्टिकोण से कुछ अवलोकन हैं जो लागू हो सकते हैं (और टिप्पणियां टिप्पणी क्षेत्र के लिए बहुत लंबी हैं)।

मेरी पहली चिंता एक लेन-देन में 2 मिलियन पंक्तियों को अपडेट करने की होगी। ओरेकल में, आप अद्यतन किए जा रहे प्रत्येक ब्लॉक की छवि से पहले लिख रहे होंगे ताकि अन्य सत्र अभी भी आपके संशोधित ब्लॉकों को पढ़े बिना लगातार पढ़ा जा सके और आपके पास रोलबैक करने की क्षमता हो। यह एक लंबा रोलबैक बनाया जा रहा है। आप आम तौर पर छोटे हिस्से में लेनदेन करने के लिए बेहतर हैं। एक बार में 1,000 रिकॉर्ड कहें।

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

ओरेकल पत्रिकाओं को रोकने के लिए बयानों पर "कोई लॉगिंग" संकेत नहीं देता है। यह बयानों को गति देता है, लेकिन आपके db को "अपरिवर्तनीय" स्थिति में छोड़ देता है। तो आप पहले बैकअप करना चाहते हैं, और तुरंत बाद में बैकअप। मुझे नहीं पता कि क्या Postgres के समान विकल्प हैं।


PostgreSQL में एक लंबे रोलबैक की समस्या नहीं है, मौजूद नहीं है। ROLBACK PostgreSQL में बहुत तेज़ है, चाहे आपका लेनदेन कितना भी बड़ा क्यों न हो। Oracle! = PostgreSQL
फ्रैंक हाइकेन

@FrankHeikens धन्यवाद, यह दिलचस्प है। मुझे यह पढना होगा कि पोस्टग्रेज पर पत्र-पत्रिका कैसे काम करती है। लेन-देन की पूरी अवधारणा को काम करने के लिए, किसी लेनदेन के दौरान डेटा के दो अलग-अलग संस्करणों को बनाए रखने की आवश्यकता होती है, छवि से पहले और बाद की छवि और यही वह तंत्र है जिसका मैं उल्लेख कर रहा हूं। एक तरह से या किसी अन्य, मुझे लगता है कि एक सीमा होगी जिसके आगे लेनदेन को बनाए रखने के संसाधन बहुत महंगे होंगे।
ग्लेन

2
@Glenn पोस्टग्रेज एक पंक्ति के संस्करणों को तालिका में स्वयं रखता है - स्पष्टीकरण के लिए यहां देखें । समझौता यह है कि आपको चारों ओर लटकने वाले 'मृत' टुपल्स मिलते हैं, जो पोस्टग्रेज में 'वैक्यूम' कहे जाने वाले एसिंक्रोनस रूप से साफ हो जाते हैं (ओरेकल को वैक्यूम की कोई आवश्यकता नहीं है क्योंकि यह टेबल में कभी भी 'मृत' पंक्तियां नहीं है)
जैक कहते हैं

आप का स्वागत है, और बल्कि
पेट भर

@Glenn PostgreSQL के पंक्ति संस्करण संगणना नियंत्रण के लिए विहित दस्तावेज़ postgresql.org/docs/current/static/mvcc-intro.html है और यह अच्छी तरह से पढ़ने लायक है। Wiki.postgresql.org/wiki/MVCC भी देखें । ध्यान दें कि मृत पंक्तियों के साथ MVCC और VACUUMकेवल आधा उत्तर है; PostgreSQL भी एक तथाकथित "लिखने आगे लॉग" (प्रभावी रूप से एक पत्रिका) एटॉमिक कमिट प्रदान करते हैं और, आदि आंशिक राईट के खिलाफ की रक्षा देखने के लिए उपयोग करता postgresql.org/docs/current/static/wal-intro.html
क्रेग रिंगर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.