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

PostgreSQL 11 में विभाजन सुधार

PostgreSQL में एक विभाजन प्रणाली को पहली बार PostgreSQL 8.1 में 2ndQuadrant संस्थापक साइमन रिग्स द्वारा जोड़ा गया था। . यह संबंध वंशानुक्रम पर आधारित था और "बाधा बहिष्करण" नामक एक क्वेरी द्वारा तालिकाओं को स्कैन किए जाने से बाहर करने के लिए एक नई तकनीक का उपयोग किया गया था। हालांकि उस समय यह एक बहुत बड़ा कदम था, आजकल इसे उपयोग करने में बोझिल होने के साथ-साथ धीमी गति से देखा जाता है, और इस प्रकार प्रतिस्थापन की आवश्यकता होती है।

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

अफसोस की बात है कि PostgreSQL 10 में इसने बहुत कुछ किया। अत्यधिक जटिलता और समय की कमी के कारण, PostgreSQL 10 के कार्यान्वयन में ऐसी कई चीजें थीं जिनकी कमी थी। रॉबर्ट हास वारसॉ के PGConf.EU में इसके बारे में बात की।

बहुत से लोगों ने PostgreSQL 11 की स्थिति को सुधारने पर काम किया; यहाँ एक पुनर्गणना में मेरा प्रयास है। मैंने इन्हें तीन क्षेत्रों में विभाजित किया है:

  1. नई विभाजन सुविधाएँ
  2. विभाजित तालिकाओं के लिए बेहतर DDL समर्थन
  3. प्रदर्शन अनुकूलन।

नई विभाजन सुविधाएं

PostgreSQL 10 में, आपकी विभाजित तालिकाएँ RANGE . में इस प्रकार हो सकती हैं और सूची मोड। ये कई वास्तविक दुनिया के डेटाबेस को आधार बनाने के लिए शक्तिशाली उपकरण हैं, लेकिन कई अन्य डिज़ाइनों के लिए आपको PostgreSQL 11 में जोड़े गए नए मोड की आवश्यकता है:HASH विभाजन . कई ग्राहकों को इसकी आवश्यकता होती है, और अमूल सुल इसे संभव बनाने के लिए कड़ी मेहनत की। यहां एक सरल उदाहरण दिया गया है:

CREATE TABLE clients (
client_id INTEGER, name TEXT
) PARTITION BY HASH (client_id);

CREATE TABLE clients_0 PARTITION OF clients
    FOR VALUES WITH (MODULUS 3, REMAINDER 0);
CREATE TABLE clients_1 PARTITION OF clients
    FOR VALUES WITH (MODULUS 3, REMAINDER 1);
CREATE TABLE clients_2 PARTITION OF clients
    FOR VALUES WITH (MODULUS 3, REMAINDER 2);

सभी विभाजनों के लिए समान मापांक मान का उपयोग करना अनिवार्य नहीं है; यह आपको बाद में और विभाजन बनाने देता है और यदि आवश्यक हो तो पंक्तियों को एक बार में एक विभाजन को पुनर्वितरित करता है।

अमित खांडेकर द्वारा लिखित एक और बहुत उपयोगी विशेषता अद्यतन की अनुमति देने की क्षमता है पंक्तियों को एक विभाजन से दूसरे विभाजन में ले जाने के लिए - अर्थात, यदि विभाजन स्तंभ के मानों में कोई परिवर्तन होता है, तो पंक्ति स्वतः ही सही विभाजन में चली जाती है। पहले, उस ऑपरेशन ने एक त्रुटि दी होगी।

अमित लैंगोट द्वारा लिखित एक और नई विशेषता और सचमुच आपका , क्या वह संघर्ष अद्यतन पर डालें विभाजित तालिकाओं पर लागू किया जा सकता है . पहले यह आदेश विफल हो जाएगा यदि यह एक विभाजित तालिका को लक्षित करता है। आप यह जानकर काम कर सकते हैं कि पंक्ति किस विभाजन में समाप्त होगी, लेकिन यह बहुत सुविधाजनक नहीं है। मैं उस कमांड के विवरण पर नहीं जाऊंगा, लेकिन अगर आपने कभी चाहा तो आपके पास UPSERT था पोस्टग्रेज में, यह बात है। एक चेतावनी यह है कि अद्यतन करें कार्रवाई पंक्ति को दूसरे विभाजन में नहीं ले जा सकती है।

अंत में, PostgreSQL 11 में एक और प्यारा नया फीचर, इस बार जीवन लड़े, बीना इमर्सन, आशुतोष बापट, राहिला सैयद, द्वारा और रॉबर्ट हास विभाजित तालिका में डिफ़ॉल्ट विभाजन के लिए समर्थन . है , अर्थात्, एक विभाजन जो उन सभी पंक्तियों को प्राप्त करता है जो किसी भी नियमित विभाजन में फिट नहीं होती हैं। हालांकि, कागज पर अच्छा होने पर, यह सुविधा उत्पादन सेटिंग्स पर बहुत सुविधाजनक नहीं है क्योंकि कुछ संचालन के लिए बिना डिफ़ॉल्ट विभाजन के साथ भारी लॉकिंग की आवश्यकता होती है। उदाहरण:एक नया विभाजन बनाने के लिए डिफ़ॉल्ट विभाजन को स्कैन करना आवश्यक है ताकि यह निर्धारित किया जा सके कि कोई भी मौजूदा पंक्तियाँ नए विभाजन की सीमाओं से मेल नहीं खाती हैं। हो सकता है कि भविष्य में इन लॉक आवश्यकताओं को कम किया जाएगा, लेकिन इस बीच मेरा सुझाव है कि इसका उपयोग न करें।

बेहतर DDL समर्थन

PostgreSQL 10 में, कुछ डीडीएल एक विभाजित तालिका पर लागू होने पर काम करने से इंकार कर देंगे, और आपको प्रत्येक विभाजन को व्यक्तिगत रूप से संसाधित करने की आवश्यकता होगी। PostgreSQL 11 में हमने इनमें से कुछ सीमाएं तय की हैं, जैसा कि साइमन रिग्स ने पहले घोषित किया था। पहले, अब आप CREATE INDEX का उपयोग कर सकते हैं विभाजित टेबल पर , वास्तव में आपके द्वारा लिखी गई एक विशेषता। इसे केवल टेडियम को कम करने के मामले के रूप में देखा जा सकता है:प्रत्येक विभाजन के लिए कमांड को दोहराने के बजाय (और सुनिश्चित करें कि प्रत्येक नए विभाजन के लिए कभी न भूलें), आप इसे केवल एक बार पैरेंट विभाजित तालिका के लिए कर सकते हैं, और यह स्वचालित रूप से लागू होता है मौजूदा और भविष्य के सभी विभाजनों के लिए।

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

इसके साथ ही, अपने द्वारा भी, आप UNIQUE भी बना सकते हैं बाधाओं, साथ ही प्राथमिक कुंजी बाधाएं . दो चेतावनी:पहला, विभाजन कुंजी प्राथमिक कुंजी का हिस्सा होना चाहिए। यह वैश्विक अनुक्रमणिका से बचते हुए, प्रति विभाजन स्थानीय रूप से अद्वितीय जाँच करने की अनुमति देता है। दूसरा, इन प्राथमिक कुंजियों को संदर्भित करने वाली विदेशी कुंजियाँ अभी तक संभव नहीं हैं। मैं उस पर PostgreSQL 12 के लिए काम कर रहा हूं।

एक और चीज जो आप कर सकते हैं (उसी व्यक्ति के लिए धन्यवाद) प्रत्येक पंक्ति के लिए बनाएं विभाजित टेबल पर ट्रिगर करता है , और क्या यह सभी विभाजनों (मौजूदा और भविष्य) पर लागू होता है। एक साइड इफेक्ट के रूप में, आप अद्वितीय . को स्थगित कर सकते हैं विभाजित तालिकाओं पर प्रतिबंध। एक चेतावनी:केवल बाद ट्रिगर्स की अनुमति है, जब तक कि हम यह नहीं समझ लेते कि पहले . से कैसे निपटें ट्रिगर जो पंक्तियों को एक अलग विभाजन में ले जाते हैं।

अंत में, विभाजित तालिका में विदेशी कुंजी हो सकती है बाधाएं . लटकते संदर्भों से बचते हुए बड़े तथ्य तालिकाओं को विभाजित करना बहुत आसान है, जिससे हर कोई घृणा करता है। मेरे सहयोगी गैब्रिएल बार्टोलिनी ने मुझे अपनी गोद से पकड़ लिया जब उन्हें पता चला कि मैंने यह लिखा और प्रतिबद्ध किया है, यह चिल्लाते हुए कि यह एक गेम-चेंजर था और मैं इतना असंवेदनशील कैसे हो सकता हूं कि उसे इस बारे में सूचित न करें। मैं, मैं मनोरंजन के लिए कोड हैक करना जारी रखता हूं।

प्रदर्शन कार्य

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

  1. क्वेरी योजना समय पर,
  2. क्वेरी पैरामीटर प्राप्त होने पर,
  3. प्रत्येक बिंदु पर जहां एक क्वेरी नोड दूसरे नोड को पैरामीटर के रूप में मान भेजता है।

यह मूल प्रणाली से एक उल्लेखनीय सुधार है जिसे केवल क्वेरी योजना समय पर लागू किया जा सकता है, और मुझे विश्वास है कि यह बहुतों को प्रसन्न करेगा।

enable_partition_pruning को बंद करने से पहले और बाद में किसी क्वेरी के लिए EXPLAIN आउटपुट की तुलना करके आप इस सुविधा को क्रिया में देख सकते हैं विकल्प। एक बहुत ही सरल उदाहरण के रूप में, बिना कांट-छांट के इस योजना की तुलना करें:

SET enable_partition_pruning TO off;
EXPLAIN (ANALYZE, COSTS off)
SELECT * FROM clientes
WHERE cliente_id = 1234;
                                QUERY PLAN                                
-------------------------------------------------------------------------
 Append (actual time=6.658..10.549 rows=1 loops=1)
   ->  Seq Scan on clientes_1 (actual time=4.724..4.724 rows=0 loops=1)
         Filter: (cliente_id = 1234)
         Rows Removed by Filter: 24978
   ->  Seq Scan on clientes_00 (actual time=1.914..1.914 rows=0 loops=1)
         Filter: (cliente_id = 1234)
         Rows Removed by Filter: 12644
   ->  Seq Scan on clientes_2 (actual time=0.017..1.021 rows=1 loops=1)
         Filter: (cliente_id = 1234)
         Rows Removed by Filter: 12570
   ->  Seq Scan on clientes_3 (actual time=0.746..0.746 rows=0 loops=1)
         Filter: (cliente_id = 1234)
         Rows Removed by Filter: 12448
   ->  Seq Scan on clientes_01 (actual time=0.648..0.648 rows=0 loops=1)
         Filter: (cliente_id = 1234)
         Rows Removed by Filter: 12482
   ->  Seq Scan on clientes_4 (actual time=0.774..0.774 rows=0 loops=1)
         Filter: (cliente_id = 1234)
         Rows Removed by Filter: 12400
   ->  Seq Scan on clientes_5 (actual time=0.717..0.717 rows=0 loops=1)
         Filter: (cliente_id = 1234)
         Rows Removed by Filter: 12477
 Planning Time: 0.375 ms
 Execution Time: 10.603 ms

प्रूनिंग के साथ उत्पादित एक के साथ:

EXPLAIN (ANALYZE, COSTS off)
SELECT * FROM clientes
WHERE cliente_id = 1234;
                                QUERY PLAN                               
----------------------------------------------------------------------
 Append (actual time=0.054..2.787 rows=1 loops=1)
   ->  Seq Scan on clientes_2 (actual time=0.052..2.785 rows=1 loops=1)
         Filter: (cliente_id = 1234)
         Rows Removed by Filter: 12570
 Planning Time: 0.292 ms
 Execution Time: 2.822 ms

मुझे यकीन है कि आपको वह सम्मोहक लगेगा। आप रिग्रेशन परीक्षण अपेक्षित फ़ाइल को पढ़कर और अधिक परिष्कृत उदाहरण देख सकते हैं।

एक अन्य आइटम आशुतोष बापट . द्वारा विभाजनवार जोड़ का परिचय था . यहां विचार यह है कि यदि आपके पास दो विभाजित टेबल हैं, और वे समान तरीकों से विभाजित हैं, तो जब वे जुड़ जाते हैं तो आप प्रत्येक विभाजन को एक तरफ से उसके मिलान वाले विभाजन में दूसरी तरफ जोड़ सकते हैं; यह प्रत्येक विभाजन को दूसरी ओर प्रत्येक विभाजन से जोड़ने से कहीं बेहतर है। तथ्य यह है कि विभाजन योजनाओं को बिल्कुल . से मेल खाना चाहिए ऐसा लग सकता है कि इसका वास्तविक दुनिया में बहुत अधिक उपयोग होने की संभावना नहीं है, लेकिन वास्तव में ऐसी कई स्थितियाँ हैं जहाँ यह लागू होता है। उदाहरण:एक ऑर्डर टेबल और उससे संबंधित ऑर्डर_आइटम टेबल। शुक्र है, इस प्रतिबंध में ढील देने के लिए पहले से ही बहुत काम है।

आखिरी आइटम जिसका मैं उल्लेख करना चाहता हूं, वह है जीवन चलके, आशुतोष बापट, द्वारा विभाजनवार समुच्चय। और रॉबर्ट हास . इस अनुकूलन का अर्थ है कि एक एकत्रीकरण जिसमें GROUP BY में विभाजन कुंजियाँ शामिल हैं खंड को प्रत्येक विभाजन की पंक्तियों को अलग-अलग एकत्रित करके निष्पादित किया जा सकता है, जो बहुत तेज़ है।

समापन विचार

इस चक्र में महत्वपूर्ण विकास के बाद, PostgreSQL के पास बहुत अधिक सम्मोहक विभाजन कहानी है। जबकि अभी भी कई सुधार किए जाने हैं, विशेष रूप से विभाजित तालिकाओं से जुड़े विभिन्न कार्यों के प्रदर्शन और समरूपता को बेहतर बनाने के लिए, अब हम एक ऐसे बिंदु पर हैं जहां घोषणात्मक विभाजन कई उपयोग के मामलों की सेवा के लिए एक बहुत ही मूल्यवान उपकरण बन गया है। 2ndQuadrant में हम इस क्षेत्र और अन्य क्षेत्रों में PostgreSQL को बेहतर बनाने के लिए कोड का योगदान करना जारी रखेंगे, जैसा कि हमने 8.0 के बाद से हर एक रिलीज़ के लिए किया है।


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. पीजी मणि स्थापित करने में विफल, mkmf.rb रूबी के लिए हेडर फाइल नहीं ढूंढ सकता (मैक ओएसएक्स 10.6.5)

  2. PostgreSQL 8.3 के बाद से OLTP प्रदर्शन

  3. इनपुट मापदंडों की चर संख्या के साथ कार्य

  4. जटिल पोस्टग्रेज क्वेरी

  5. PostgreSQL:PostgreSQL में टेबल दिखाएं