PostgreSQL
 sql >> डेटाबेस >  >> RDS >> PostgreSQL

मैं PostgreSQL में बड़े गैर-अवरुद्ध अद्यतन कैसे करूं?

स्तंभ / पंक्ति

<ब्लॉककोट>

... मुझे पूरे ऑपरेशन में लेन-देन की अखंडता बनाए रखने की आवश्यकता नहीं है, क्योंकि मुझे पता है कि मैं जो कॉलम बदल रहा हूं वह अपडेट के दौरान लिखा या पढ़ा नहीं जा रहा है।

कोई भी UPDATE PostgreSQL के MVCC मॉडल में पूरी पंक्ति . का एक नया संस्करण लिखता है . यदि समवर्ती लेन-देन कोई भी change बदलते हैं एक ही पंक्ति के स्तंभ, समय लेने वाली समवर्ती समस्याएँ उत्पन्न होती हैं। मैनुअल में विवरण। वही स्तंभ जानना समवर्ती लेनदेन से प्रभावित नहीं होगा कुछ से बचा जाता है संभावित जटिलताएं, लेकिन अन्य नहीं।

सूचकांक

<ब्लॉककोट>

किसी विषय से हटकर चर्चा की ओर जाने से बचने के लिए, मान लें कि 35 मिलियन स्तंभों के लिए स्थिति के सभी मान वर्तमान में समान (गैर-शून्य) मान पर सेट हैं, इस प्रकार एक अनुक्रमणिका बेकार हो जाती है।

संपूर्ण तालिका को अपडेट करते समय (या इसके प्रमुख भाग) पोस्टग्रेज कभी किसी अनुक्रमणिका का उपयोग नहीं करता . अनुक्रमिक स्कैन तेज़ होता है जब सभी या अधिकतर पंक्तियों को पढ़ना होता है। इसके विपरीत:अनुक्रमणिका रखरखाव का अर्थ है UPDATE के लिए अतिरिक्त लागत ।

प्रदर्शन

<ब्लॉककोट>

उदाहरण के लिए, मान लें कि मेरे पास 35 मिलियन पंक्तियों के साथ "आदेश" नामक एक तालिका है, और मैं यह करना चाहता हूं:

UPDATE orders SET status = null;

मैं समझता हूं कि आप अधिक सामान्य समाधान का लक्ष्य बना रहे हैं (नीचे देखें)। लेकिन वास्तविक प्रश्न को संबोधित करने के लिए पूछा गया:इससे मामला मिलीसेकंड . में निपटा जा सकता है , तालिका आकार की परवाह किए बिना:

ALTER TABLE orders DROP column status
                 , ADD  column status text;

मैनुअल (पोस्टग्रेज 10 तक):

<ब्लॉककोट>

जब ADD COLUMN के साथ एक कॉलम जोड़ा जाता है , तालिका में सभी मौजूदा पंक्तियों को कॉलम के डिफ़ॉल्ट मान (NULL . के साथ प्रारंभ किया जाता है अगर नहीं DEFAULT खंड निर्दिष्ट है)। अगर कोई DEFAULT नहीं है खंड, यह केवल एक मेटाडेटा परिवर्तन है [...]

मैनुअल (पोस्टग्रेज 11 के बाद से):

<ब्लॉककोट>

जब ADD COLUMN के साथ एक कॉलम जोड़ा जाता है और एक गैर-वाष्पशील DEFAULT निर्दिष्ट है, डिफ़ॉल्ट का मूल्यांकन स्टेटमेंट के समय किया जाता है और परिणाम तालिका के मेटाडेटा में संग्रहीत होता है। उस मान का उपयोग सभी मौजूदा पंक्तियों के कॉलम के लिए किया जाएगा। यदि नहीं DEFAULT निर्दिष्ट है, NULL का उपयोग किया जाता है। किसी भी स्थिति में तालिका के पुनर्लेखन की आवश्यकता नहीं है।

एक अस्थिर DEFAULT . के साथ एक कॉलम जोड़ना या मौजूदा कॉलम के प्रकार को बदलने के लिए पूरी तालिका और उसकी अनुक्रमणिका को फिर से लिखना होगा। [...]

और:

<ब्लॉककोट>

DROP COLUMN फॉर्म कॉलम को भौतिक रूप से नहीं हटाता है, लेकिन बस इसे SQL ऑपरेशंस के लिए अदृश्य बना देता है। तालिका में बाद में सम्मिलित और अद्यतन संचालन कॉलम के लिए एक शून्य मान संग्रहीत करेगा। इस प्रकार, एक कॉलम छोड़ना त्वरित है लेकिन यह आपकी तालिका के ऑन-डिस्क आकार को तुरंत कम नहीं करेगा, क्योंकि ड्रॉप किए गए कॉलम द्वारा कब्जा कर लिया गया स्थान पुनः प्राप्त नहीं किया गया है। समय के साथ स्थान को पुनः प्राप्त कर लिया जाएगा क्योंकि मौजूदा पंक्तियों को अद्यतन किया जाता है।

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

यदि आपके पास कोई कॉलम डिफ़ॉल्ट है जिसे आप रखना चाहते हैं, तो उसे एक अलग कमांड में वापस जोड़ें . इसे उसी कमांड में करने से यह तुरंत सभी पंक्तियों पर लागू हो जाता है। देखें:

  • टेबल लॉक के बिना नया कॉलम जोड़ें?

वास्तव में डिफ़ॉल्ट लागू करने के लिए, इसे बैचों में करने पर विचार करें:

  • क्या PostgreSQL गैर-नल डिफ़ॉल्ट वाले कॉलम जोड़ने को अनुकूलित करता है?

सामान्य समाधान

dblink एक अन्य उत्तर में उल्लेख किया गया है। यह "रिमोट" पोस्टग्रेज डेटाबेस को निहित अलग कनेक्शन में एक्सेस करने की अनुमति देता है। "दूरस्थ" डेटाबेस वर्तमान डेटाबेस हो सकता है, जिससे "स्वायत्त लेनदेन" प्राप्त हो सकता है :"रिमोट" डीबी में फ़ंक्शन जो लिखता है वह प्रतिबद्ध है और इसे वापस नहीं लाया जा सकता है।

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

यदि आपके पास समवर्ती पहुंच नहीं है, तो यह शायद ही उपयोगी है - ROLLBACK . से बचने के अलावा एक अपवाद के बाद। SAVEPOINT . पर भी विचार करें उस मामले के लिए।

अस्वीकरण

सबसे पहले, बहुत सारे छोटे लेनदेन वास्तव में अधिक महंगे हैं। यह केवल बड़ी तालिकाओं के लिए उपयुक्त है . मीठा स्थान कई कारकों पर निर्भर करता है।

यदि आप सुनिश्चित नहीं हैं कि आप क्या कर रहे हैं:एक ही लेन-देन सुरक्षित तरीका है . इसके लिए ठीक से काम करने के लिए, टेबल पर समवर्ती संचालन को साथ खेलना होगा। उदाहरण के लिए:समवर्ती लिखता है एक पंक्ति को उस विभाजन में ले जा सकता है जो माना जाता है कि पहले से ही संसाधित है। या समवर्ती पठन असंगत मध्यस्थ राज्यों को देख सकते हैं। आपको चेतावनी दी गई है।

चरण-दर-चरण निर्देश

अतिरिक्त मॉड्यूल dblink को पहले स्थापित करने की आवश्यकता है:

  • PostgreSQL में dblink का उपयोग (इंस्टॉल) कैसे करें?

dblink के साथ कनेक्शन स्थापित करना आपके डीबी क्लस्टर के सेटअप और सुरक्षा नीतियों पर निर्भर करता है। यह पेचीदा हो सकता है। अधिक के साथ संबंधित बाद के उत्तर डबलिंक से कैसे जुड़ें :

  • फ़ंक्शन बंद होने पर भी UDF में लगातार इंसर्ट करना

एक FOREIGN SERVER बनाएं और एक USER MAPPING जैसा कि वहां कनेक्शन को सरल और सुव्यवस्थित करने के निर्देश दिए गए हैं (जब तक कि आपके पास पहले से एक न हो)।
एक serial PRIMARY KEY मानते हुए कुछ अंतराल के साथ या बिना।

CREATE OR REPLACE FUNCTION f_update_in_steps()
  RETURNS void AS
$func$
DECLARE
   _step int;   -- size of step
   _cur  int;   -- current ID (starting with minimum)
   _max  int;   -- maximum ID
BEGIN
   SELECT INTO _cur, _max  min(order_id), max(order_id) FROM orders;
                                        -- 100 slices (steps) hard coded
   _step := ((_max - _cur) / 100) + 1;  -- rounded, possibly a bit too small
                                        -- +1 to avoid endless loop for 0
   PERFORM dblink_connect('myserver');  -- your foreign server as instructed above

   FOR i IN 0..200 LOOP                 -- 200 >> 100 to make sure we exceed _max
      PERFORM dblink_exec(
       $$UPDATE public.orders
         SET    status = 'foo'
         WHERE  order_id >= $$ || _cur || $$
         AND    order_id <  $$ || _cur + _step || $$
         AND    status IS DISTINCT FROM 'foo'$$);  -- avoid empty update

      _cur := _cur + _step;

      EXIT WHEN _cur > _max;            -- stop when done (never loop till 200)
   END LOOP;

   PERFORM dblink_disconnect();
END
$func$  LANGUAGE plpgsql;

कॉल करें:

SELECT f_update_in_steps();

आप अपनी आवश्यकताओं के अनुसार किसी भी भाग को पैरामीटराइज़ कर सकते हैं:तालिका का नाम, स्तंभ का नाम, मान, ... बस SQL ​​इंजेक्शन से बचने के लिए पहचानकर्ताओं को साफ करना सुनिश्चित करें:

  • तालिका नाम PostgreSQL फ़ंक्शन पैरामीटर के रूप में

खाली अपडेट से बचें:

  • मैं कैसे (या मैं कर सकता हूं) एकाधिक स्तंभों पर DISTINCT का चयन कैसे करूं?


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PostGIS का उपयोग करके दिए गए बिंदु के लिए निकटतम पड़ोसियों का पता लगाएं?

  2. एकाधिक थ्रेड्स का उपयोग करके फ़ाइल लिखना

  3. PostgreSQL में दो डेटाबेस के बीच डेटा की तुलना कैसे करें?

  4. दो स्तंभों के संयोजन पर अद्वितीय बाधा?

  5. मैं PostgreSQL 9.5 में एक int डेटाटाइप के लिए आकार सीमा कैसे निर्धारित कर सकता हूं?