2009-06-07 12 views
19

हमारे पास एक विशिष्ट अनुप्रयोग है जो पोस्टग्रेएसक्यूएल 8.3 को भंडारण बैकएंड के रूप में उपयोग करता है (पायथन और psycopg2 का उपयोग करके)। महत्वपूर्ण सारणी में हम जो ऑपरेशन करते हैं, वे अधिकांश मामलों में आवेषण या अपडेट होते हैं (शायद ही कभी हटाते हैं या चयन करते हैं)।मैं PostgreSQL में ऑपरेशंस को अपडेट/प्रतिस्थापित कैसे कर सकता हूं?

स्वच्छता कारणों से हमने अपना खुद का Data Mapper बनाया है-जैसी परत जो उचित रूप से अच्छी तरह से काम करती है, लेकिन इसमें एक बड़ी बाधा, अद्यतन प्रदर्शन है। बेशक, मैं परिदृश्य को प्रतिस्थापित/प्रतिस्थापित करने की उम्मीद नहीं कर रहा हूं, 'एक खाली तालिका में डालें' के रूप में तेज़ी से, लेकिन थोड़ा करीब होना अच्छा लगेगा।

ध्यान दें कि यह प्रणाली समवर्ती अद्यतन

हम हमेशा एक अद्यतन पर प्रत्येक पंक्तियों के सभी क्षेत्रों की स्थापना की है, जो शब्दावली, जहां मैं अपने परीक्षण में शब्द 'की जगह' का उपयोग में देखा जा सकता से मुक्त है। मैं अब तक हमारे अद्यतन समस्या में दो तरीकों की कोशिश की है:

  1. एक replace() प्रक्रिया है कि अद्यतन करने के लिए पंक्तियों की एक सरणी लेता बनाएँ:

    CREATE OR REPLACE FUNCTION replace_item(data item[]) RETURNS VOID AS $$ 
    BEGIN 
        FOR i IN COALESCE(array_lower(data,1),0) .. COALESCE(array_upper(data,1),-1) LOOP 
         UPDATE item SET a0=data[i].a0,a1=data[i].a1,a2=data[i].a2 WHERE key=data[i].key; 
        END LOOP; 
    END; 
    $$ LANGUAGE plpgsql 
    
  2. एक insert_or_replace नियम बनाएं ताकि सब कुछ है, लेकिन कभी नष्ट हो जाता है बहु पंक्ति सम्मिलित करता

    CREATE RULE "insert_or_replace" AS 
        ON INSERT TO "item" 
        WHERE EXISTS(SELECT 1 FROM item WHERE key=NEW.key) 
        DO INSTEAD 
         (UPDATE item SET a0=NEW.a0,a1=NEW.a1,a2=NEW.a2 WHERE key=NEW.key); 
    

गु ese दोनों अद्यतन एक निष्पक्ष बिट को गति, हालांकि बाद धीमा थोड़ा सम्मिलित करता है:

  • सभी परीक्षण डेटाबेस के रूप में एक ही कंप्यूटर पर चलाए जा रहे हैं: परीक्षण चालन के बारे में

    Multi-row insert   : 50000 items inserted in 1.32 seconds averaging 37807.84 items/s 
    executemany() update  : 50000 items updated in 26.67 seconds averaging 1874.57 items/s 
    update_andres    : 50000 items updated in 3.84 seconds averaging 13028.51 items/s 
    update_merlin83 (i/d/i) : 50000 items updated in 1.29 seconds averaging 38780.46 items/s 
    update_merlin83 (i/u)  : 50000 items updated in 1.24 seconds averaging 40313.28 items/s 
    replace_item() procedure : 50000 items replaced in 3.10 seconds averaging 16151.42 items/s 
    Multi-row insert_or_replace: 50000 items inserted in 2.73 seconds averaging 18296.30 items/s 
    Multi-row insert_or_replace: 50000 items replaced in 2.02 seconds averaging 24729.94 items/s 
    

    रैंडम नोट्स रहता है; लोकलहोस्ट से कनेक्ट करना

  • 500 आइटमों के बैच में डेटाबेस पर सम्मिलित और अद्यतन लागू होते हैं, प्रत्येक अपने लेनदेन में भेजे जाते हैं (अद्यतन)।
  • सभी अद्यतन/प्रतिस्थापन परीक्षण उसी मान का उपयोग करते थे जो पहले से ही डेटाबेस में थे।
  • सभी डेटा psycopg2 अनुकूल() फ़ंक्शन का उपयोग करके बच निकला था।
  • सभी तालिकाओं छोटा कर दिया और उपयोग करने से पहले वैक्यूम कर रहे हैं (जोड़ा, पिछले रन ही काट-छांट हुआ में)
  • तालिका इस प्रकार है:

    CREATE TABLE item (
        key MACADDR PRIMARY KEY, 
        a0 VARCHAR, 
        a1 VARCHAR, 
        a2 VARCHAR 
    ) 
    

तो, असली सवाल यह है: मैं ऑपरेशन को थोड़ा सा अद्यतन/प्रतिस्थापित कैसे कर सकता हूं? (मुझे लगता है कि ये निष्कर्ष 'पर्याप्त अच्छे' हो सकते हैं, लेकिन मैं एसओ भीड़ को टैप किए बिना छोड़ना नहीं चाहता :)

कोई भी एक और सुरुचिपूर्ण repl_item(), या सबूत की ओर संकेत करता है कि मेरे परीक्षण पूरी तरह से हैं टूटा हुआ स्वागत है।

यदि आप पुन: पेश करने का प्रयास करना चाहते हैं तो परीक्षण स्क्रिप्ट here उपलब्ध है। हालांकि इसे पहले जांचना याद रखें ... यह वर्क्सफ़ोरमे है, लेकिन ...

आपको डीबी संपादित करने की आवश्यकता होगी।अपने सेटअप के अनुरूप कनेक्ट() लाइन।

संपादित

#postgresql में एन्ड्रेस @ freenode मैं एक एकल क्वेरी अद्यतन के साथ एक और परीक्षण करने के लिए धन्यवाद; एक बहु-पंक्ति सम्मिलन की तरह (उपरोक्त update_andres के रूप में सूचीबद्ध)। (I

UPDATE item 
SET a0=i.a0, a1=i.a1, a2=i.a2 
FROM (VALUES ('00:00:00:00:00:01', 'v0', 'v1', 'v2'), 
      ('00:00:00:00:00:02', 'v3', 'v4', 'v5'), 
      ... 
    ) AS i(key, a0, a1, a2) 
WHERE item.key=i.key::macaddr 

संपादित

#postgresql @ नीचे मैं एक डालने करने वाली अस्थायी साथ एक और परीक्षण किया है freenode और सुराही/JWP में merlin83 के लिए धन्यवाद/हटाने/डालने दृष्टिकोण ("के रूप में सूचीबद्ध update_merlin83/डी/i) "ऊपर)।

INSERT INTO temp_item (key, a0, a1, a2) 
    VALUES (
     ('00:00:00:00:00:01', 'v0', 'v1', 'v2'), 
     ('00:00:00:00:00:02', 'v3', 'v4', 'v5'), 
     ...); 

DELETE FROM item 
USING temp_item 
WHERE item.key=temp_item.key; 

INSERT INTO item (key, a0, a1, a2) 
    SELECT key, a0, a1, a2 
    FROM temp_item; 

मेरे पेट लग रहा है कि इन परीक्षणों वास्तविक दुनिया परिदृश्य में प्रदर्शन करने के लिए बहुत प्रतिनिधि नहीं हैं, लेकिन मुझे लगता है कि मतभेदों को काफी महान आगे की जांच पड़ताल के लिए सबसे होनहार दृष्टिकोण का एक संकेत देने के लिए कर रहे हैं। Perftest.py स्क्रिप्ट में उन सभी के लिए भी सभी अपडेट शामिल हैं जो इसे देखना चाहते हैं। हालांकि यह काफी बदसूरत है, @ freenode ने बताया कि मैं एक डालने करने वाली अस्थायी/अद्यतन संस्करण के साथ परीक्षण करना चाहिए तो अपने चश्मे :)

संपादित

#postgresql में एन्ड्रेस मत भूलना (के रूप में सूचीबद्ध "ऊपर_merlin83 (i/u)" ऊपर)।

INSERT INTO temp_item (key, a0, a1, a2) 
    VALUES (
     ('00:00:00:00:00:01', 'v0', 'v1', 'v2'), 
     ('00:00:00:00:00:02', 'v3', 'v4', 'v5'), 
     ...); 

UPDATE item 
SET a0=temp_item.a0, a1=temp_item.a1, a2=temp_item.a2 
FROM temp_item 
WHERE item.key=temp_item.key 

संपादित

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

+0

कैसे प्रासंगिक तालिकाओं में अनुक्रमित रहे हैं? कोई विदेशी केई? –

+0

परीक्षण-स्क्रिप्ट में नहीं, नहीं। असली दुनिया में, एक। –

+0

क्या आप अपने 'अपडेट' के 'एक्सप्लिन विश्लेषण' पोस्ट कर सकते हैं? मैं जानना चाहता हूं कि अनुमानक क्या सोचता है। – Sean

उत्तर

1

आपके insert_or_replace में। इस प्रयास करें:

WHERE EXISTS(SELECT 1 FROM item WHERE key=NEW.key LIMIT 1) 
बजाय

WHERE EXISTS(SELECT 1 FROM item WHERE key=NEW.key) 

टिप्पणी में बताया गया है, कि शायद कुछ भी नहीं होगा। मुझे बस इतना जोड़ना है कि आप इंडेक्स को हटाकर हमेशा INSERT/UPDATE प्रदर्शन को तेज कर सकते हैं। ऐसा संभवतः ऐसा कुछ नहीं होगा जब तक आप पाते हैं कि आपकी तालिका अधिक से अधिक नहीं है, लेकिन कम से कम जांच की जानी चाहिए।

+0

शायद यह अनावश्यक है - दस्तावेज़ों से उद्धरण (http://www.postgresql.org/docs/current/static/functions -subquery.html # एएन 15270): "सबक्वायरी आमतौर पर केवल यह निर्धारित करने के लिए पर्याप्त रूप से निष्पादित की जाएगी कि कम से कम एक पंक्ति वापस आती है, पूरा होने के सभी तरीके नहीं।" –

+0

आह, धन्यवाद। पता नहीं था कि कितने स्मार्ट EXISTS था। अब मैं करता हूँ। :) – chaos

+0

कुंजी अद्वितीय है, इसलिए यह केवल एक पंक्ति वापस आ जाएगी। फिर भी, मैंने कोशिश की, और किसी भी तरह प्रदर्शन में कोई उल्लेखनीय परिवर्तन नहीं हुआ। हालांकि धन्यवाद! –

1

ओरेकल में, तालिका को लॉक करने से निश्चित रूप से मदद मिलेगी। आप पोस्टग्रेएसक्यूएल के साथ भी कोशिश कर सकते हैं।

+0

मैंने सभी लेनदेन में लॉक की गई तालिका के साथ सभी परीक्षण चलाने की कोशिश की; कोई परिवर्तन नहीं होता है। –

2

मैं कुछ महीने पहले एक ऐसी ही स्थिति थी और एक देखते हिस्सा/लेन-देन आकार से बड़ा गति को बढ़ावा देने के लिए हो रही समाप्त हो गया। आप परीक्षा के दौरान चेकपॉइंट चेतावनी के लिए लॉग भी जांचना चाहेंगे और उचित रूप से ट्यून कर सकते हैं।

+0

मैं निश्चित रूप से चेकपॉइंट चेतावनियों की तलाश करूंगा, यह बहुत प्रासंगिक दिखता है; धन्यवाद! –

2

लगता है कि आपने वाल का उपयोग करने से लाभ देखना चाहते हैं एक यूपीएस के साथ (आगे लॉगिंग लिखें) आपके अपडेट को कैश करने के बीच डिस्क लिखता है।

wal_buffers यह सेटिंग बफर WAL (आगे लॉग लिखें) की संख्या तय कर सकती है। यदि आपके डेटाबेस में कई लिखने वाले लेन-देन हैं, तो डिफ़ॉल्ट रूप से इस मान को थोड़ा अधिक सेट करने से डिस्क स्थान का बेहतर उपयोग हो सकता है। प्रयोग और निर्णय लें।256-512 के मेमोरी के अनुरूप 32-264 की अच्छी शुरुआत होगी।

http://www.varlena.com/GeneralBits/Tidbits/perf.html

4

हमेशा की तरह मैं पृ ये चीज़ें है: अस्थायी तालिका (बगैर किसी अड़चन) प्रति का उपयोग कर, विलय (मज़ा हिस्सा), लाभ में लक्ष्य तालिका से मेल खाने कच्चे डेटा लोड।

मैं इन स्थितियों के लिए विशेष रूप से एक merge_by_key समारोह लिखा है:

http://mbk.projects.postgresql.org/

डॉक्स बहुत अनुकूल नहीं हैं, लेकिन मैं इसे एक अच्छा दृश्य दिखाई देता है सुझाव देना चाहेंगे।

+0

सामान्य प्रक्रिया के बिंदु: किसी भी नेटवर्क राउंड-ट्रिप लागत से बचने के लिए अस्थायी रूप से लोड करें और प्रत्येक लोड की गई पंक्ति के लिए एकाधिक कर्सर (पोर्टल) बनाने से बचने के लिए (हाँ, यह निष्पादन के साथ तेज़ है, लेकिन COPY wtf-pwns-it दक्षता के लिए wrt)। नियम/ट्रिगर बनाने से बचने के लिए विलय समारोह/प्रक्रिया का उपयोग करें जो एक सम्मिलित कथन के अर्थशास्त्र को बदलता है। मैंने इसे दोनों तरीकों से किया है, और मैंने हमेशा विलय प्रक्रिया को प्राथमिकता दी है क्योंकि यह स्पष्ट है। यदि मर्ज प्रक्रिया पर्याप्त कुशल नहीं है, तो आपको इंडेक्स निलंबन (मनोरंजन)/विभाजन या http://pgfoundry.org/projects/pgbulkload/ पर देखना होगा – jwp

संबंधित मुद्दे

 संबंधित मुद्दे