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

PostgreSQL में डेटा विभाजन के लिए एक गाइड

डेटा विभाजन क्या है?

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

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

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

यह विभाजित तालिकाओं में बाधाओं को जोड़कर किया जाता है जो परिभाषित करते हैं कि प्रत्येक तालिका में किस डेटा की अनुमति है, और एक अच्छे डिज़ाइन के साथ, हम क्वेरी प्लानर को पूरी चीज़ के बजाय डेटा के एक छोटे सबसेट को स्कैन कर सकते हैं।

क्या किसी तालिका को विभाजित किया जाना चाहिए?

विभाजन सही होने पर टेबल पर प्रदर्शन में काफी सुधार कर सकता है, लेकिन अगर गलत किया जाता है या जब जरूरत नहीं होती है, तो यह प्रदर्शन को खराब कर सकता है, यहां तक ​​​​कि अनुपयोगी भी।

टेबल कितनी बड़ी है?

विभाजन से पहले एक तालिका कितनी बड़ी होनी चाहिए, इसके लिए कोई वास्तविक कठोर नियम नहीं है, लेकिन डेटाबेस एक्सेस रुझानों के आधार पर, डेटाबेस उपयोगकर्ता और व्यवस्थापक एक विशिष्ट तालिका पर प्रदर्शन को देखना शुरू कर देंगे क्योंकि यह बड़ा हो जाता है। सामान्य तौर पर, विभाजन पर तभी विचार किया जाना चाहिए जब कोई कहता है "मैं X नहीं कर सकता क्योंकि तालिका बहुत बड़ी है।" कुछ मेजबानों के लिए, 200 जीबी विभाजन का सही समय हो सकता है, दूसरों के लिए, यह विभाजन का समय हो सकता है जब यह 1 टीबी तक पहुंच जाए।

यदि तालिका "बहुत बड़ी" होने के लिए निर्धारित है, तो यह एक्सेस पैटर्न को देखने का समय है। या तो डेटाबेस तक पहुंचने वाले अनुप्रयोगों को जानने के द्वारा, या लॉग की निगरानी करके और pgBadger जैसी किसी चीज़ के साथ क्वेरी रिपोर्ट तैयार करके, हम देख सकते हैं कि किसी तालिका तक कैसे पहुँचा जाता है, और इस पर निर्भर करते हुए कि हमारे पास एक अच्छी विभाजन रणनीति के विकल्प हो सकते हैं।

pgBadger के बारे में और इसका उपयोग करने के तरीके के बारे में अधिक जानने के लिए, कृपया pgBadger के बारे में हमारा पिछला लेख देखें।

क्या टेबल ब्लोट एक समस्या है?

अद्यतन और हटाई गई पंक्तियों के परिणामस्वरूप मृत टुपल्स होते हैं जिन्हें अंततः साफ करने की आवश्यकता होती है। वैक्यूमिंग टेबल, चाहे मैन्युअल रूप से या स्वचालित रूप से, तालिका में प्रत्येक पंक्ति पर जाती है और यह निर्धारित करती है कि इसे पुनः प्राप्त किया जाना है या अकेला छोड़ दिया गया है। तालिका जितनी बड़ी होगी, इस प्रक्रिया में उतना ही अधिक समय लगेगा, और अधिक सिस्टम संसाधनों का उपयोग किया जाएगा। यहां तक ​​कि अगर किसी तालिका का 90% डेटा अपरिवर्तित है, तो उसे हर बार वैक्यूम चलाने पर स्कैन किया जाना चाहिए। तालिका को विभाजित करने से उस तालिका को कम करने में मदद मिल सकती है जिसे छोटे लोगों को वैक्यूम करने की आवश्यकता होती है, स्कैन किए जाने वाले अपरिवर्तनीय डेटा की मात्रा को कम करने, समग्र रूप से कम समय में वैक्यूम करने, और सिस्टम रखरखाव के बजाय उपयोगकर्ता की पहुंच के लिए अधिक सिस्टम संसाधनों को मुक्त करने में मदद मिल सकती है।

डेटा कैसे मिटाया जाता है, अगर बिल्कुल भी?

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

टेबल को कैसे विभाजित किया जाना चाहिए?

एक्सेस पैटर्न की कुंजियाँ WHERE क्लॉज़ और JOIN शर्तों में हैं। जब भी कोई क्वेरी WHERE और JOIN क्लॉज़ में कॉलम निर्दिष्ट करती है, तो यह डेटाबेस को "यह वह डेटा है जो मुझे चाहिए" बताता है। इन खण्डों को लक्षित करने वाले अनुक्रमितों को डिजाइन करने की तरह, विभाजन रणनीतियाँ डेटा को अलग करने के लिए इन स्तंभों को लक्षित करने पर निर्भर करती हैं और क्वेरी को यथासंभव कम विभाजन तक पहुँचाती हैं।

उदाहरण:

  1. एक लेन-देन तालिका, एक दिनांक कॉलम के साथ जो हमेशा एक क्लॉज में उपयोग किया जाता है।
  2. स्थान कॉलम के साथ एक ग्राहक तालिका, जैसे निवास का देश जो हमेशा क्लॉज में उपयोग किया जाता है।

विभाजन के लिए ध्यान केंद्रित करने के लिए सबसे आम कॉलम आमतौर पर टाइमस्टैम्प होते हैं, क्योंकि आमतौर पर डेटा का एक बड़ा हिस्सा ऐतिहासिक जानकारी होता है, और संभवतः अलग-अलग समय समूहों में फैला हुआ अनुमानित डेटा होगा।

डेटा स्प्रेड निर्धारित करें

एक बार जब हम पहचान लेते हैं कि किस कॉलम पर विभाजन करना है, तो हमें डेटा के प्रसार पर एक नज़र डालनी चाहिए, जिसका लक्ष्य विभाजन आकार बनाना है जो डेटा को अलग-अलग चाइल्ड पार्टिशन में यथासंभव समान रूप से फैलाता है।

severalnines=# SELECT DATE_TRUNC('year', view_date)::DATE, COUNT(*) FROM website_views GROUP BY 1 ORDER BY 1;
 date_trunc |  count
------------+----------
 2013-01-01 | 11625147
 2014-01-01 | 20819125
 2015-01-01 | 20277739
 2016-01-01 | 20584545
 2017-01-01 | 20777354
 2018-01-01 |   491002
(6 rows)

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

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

विभाजित तालिका बनाना

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

यह एक मूल तालिका होने से संचालित होता है जो अंततः खाली हो जाएगी (या यदि यह एक नई तालिका है तो खाली रहेगी), और चाइल्ड टेबल जो मूल तालिका में शामिल हैं। जब पैरेंट टेबल से पूछताछ की जाती है, तो चाइल्ड टेबल पर लागू INHERIT के कारण डेटा के लिए चाइल्ड टेबल भी खोजे जाते हैं। हालाँकि, चूंकि चाइल्ड टेबल में केवल माता-पिता के डेटा के सबसेट होते हैं, हम टेबल पर एक CONSTRAINT जोड़ते हैं जो एक CHECK करता है और यह सत्यापित करता है कि डेटा टेबल में अनुमत डेटा से मेल खाता है। यह दो चीजें करता है:पहला यह उस डेटा को मना कर देता है जो संबंधित नहीं है, और दूसरा यह क्वेरी प्लानर को बताता है कि इस तालिका में केवल इस CHECK CONSTRAINT से मेल खाने वाले डेटा की अनुमति है, इसलिए यदि डेटा की खोज करना जो तालिका से मेल नहीं खाता है, तो डॉन ' इसे खोजने की भी जहमत नहीं उठाई।

अंत में, हम पैरेंट टेबल पर एक ट्रिगर लागू करते हैं जो एक संग्रहित प्रक्रिया को निष्पादित करता है जो यह तय करती है कि कौन सी चाइल्ड टेबल डेटा डालना है।

टेबल बनाएं

पैरेंट टेबल बनाना किसी भी अन्य टेबल क्रिएशन की तरह है।

severalnines=# CREATE TABLE data_log (data_log_sid SERIAL PRIMARY KEY,
  date TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW(),
  event_details VARCHAR);
CREATE TABLE

चाइल्ड टेबल बनाएं

चाइल्ड टेबल बनाना समान है, लेकिन इसमें कुछ अतिरिक्त शामिल हैं। संगठनात्मक खातिर, हमारे पास एक अलग स्कीमा में हमारे चाइल्ड टेबल मौजूद होंगे। प्रत्येक चाइल्ड टेबल के लिए ऐसा करें, तदनुसार विवरण बदलते हुए।

नोट:नेक्स्टवल () में इस्तेमाल किए गए सीक्वेंस का नाम उस सीक्वेंस से आता है, जिसे पैरेंट ने बनाया था। यह सभी चाइल्ड टेबल के लिए समान क्रम का उपयोग करने के लिए महत्वपूर्ण है।

severalnines=# CREATE SCHEMA part;
CREATE SCHEMA

severalnines=# CREATE TABLE part.data_log_2018 (data_log_sid integer DEFAULT nextval('public.data_log_data_log_sid_seq'::regclass),
  date TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW(),
  event_details VARCHAR)
 INHERITS (public.data_log);
CREATE TABLE

severalnines=# ALTER TABLE ONLY part.data_log_2018
    ADD CONSTRAINT data_log_2018_pkey PRIMARY KEY (data_log_sid);
ALTER TABLE

severalnines=# ALTER TABLE part.data_log_2018 ADD CONSTRAINT data_log_2018_date CHECK (date >= '2018-01-01' AND date < '2019-01-01');
ALTER TABLE

फ़ंक्शन और ट्रिगर बनाएं

अंत में, हम अपनी संग्रहित प्रक्रिया बनाते हैं, और ट्रिगर को हमारी मूल तालिका में जोड़ते हैं।

severalnines=# CREATE OR REPLACE FUNCTION 
 public.insert_trigger_table()
  RETURNS trigger
  LANGUAGE plpgsql
 AS $function$
 BEGIN
     IF NEW.date >= '2018-01-01' AND NEW.date < '2019-01-01' THEN
         INSERT INTO part.data_log_2018 VALUES (NEW.*);
         RETURN NULL;
     ELSIF NEW.date >= '2019-01-01' AND NEW.date < '2020-01-01' THEN
         INSERT INTO part.data_log_2019 VALUES (NEW.*);
         RETURN NULL;
     END IF;
 END;
 $function$;
CREATE FUNCTION

severalnines=# CREATE TRIGGER insert_trigger BEFORE INSERT ON data_log FOR EACH ROW EXECUTE PROCEDURE insert_trigger_table();
CREATE TRIGGER

इसका परीक्षण करें

अब जबकि यह सब बन चुका है, आइए इसका परीक्षण करते हैं। इस परीक्षण में, मैंने 2013 - 2020 को कवर करते हुए और अधिक वार्षिक तालिकाएँ जोड़ी हैं।

नोट:नीचे सम्मिलित प्रतिक्रिया 'INSERT 0 0' है, जो यह सुझाव देगी कि उसने कुछ भी सम्मिलित नहीं किया है। इसे इस लेख में बाद में संबोधित किया जाएगा।

severalnines=# INSERT INTO data_log (date, event_details) VALUES ('2018-08-20 15:22:14', 'First insert');
INSERT 0 0

severalnines=# SELECT * FROM data_log WHERE date >= '2018-08-01' AND date < '2018-09-01';
 data_log_sid |            date            | event_details
--------------+----------------------------+---------------
            1 | 2018-08-17 23:01:38.324056 | First insert
(1 row)

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

severalnines=# EXPLAIN ANALYZE SELECT * FROM data_log;
                                                    QUERY PLAN
------------------------------------------------------------------------------------------------------------------
 Append  (cost=0.00..130.12 rows=5813 width=44) (actual time=0.016..0.019 rows=1 loops=1)
   ->  Seq Scan on data_log  (cost=0.00..1.00 rows=1 width=44) (actual time=0.007..0.007 rows=0 loops=1)
   ->  Seq Scan on data_log_2015  (cost=0.00..21.30 rows=1130 width=44) (actual time=0.001..0.001 rows=0 loops=1)
   ->  Seq Scan on data_log_2013  (cost=0.00..17.80 rows=780 width=44) (actual time=0.001..0.001 rows=0 loops=1)
   ->  Seq Scan on data_log_2014  (cost=0.00..17.80 rows=780 width=44) (actual time=0.001..0.001 rows=0 loops=1)
   ->  Seq Scan on data_log_2016  (cost=0.00..17.80 rows=780 width=44) (actual time=0.001..0.001 rows=0 loops=1)
   ->  Seq Scan on data_log_2017  (cost=0.00..17.80 rows=780 width=44) (actual time=0.001..0.001 rows=0 loops=1)
   ->  Seq Scan on data_log_2018  (cost=0.00..1.02 rows=2 width=44) (actual time=0.005..0.005 rows=1 loops=1)
   ->  Seq Scan on data_log_2019  (cost=0.00..17.80 rows=780 width=44) (actual time=0.001..0.001 rows=0 loops=1)
   ->  Seq Scan on data_log_2020  (cost=0.00..17.80 rows=780 width=44) (actual time=0.001..0.001 rows=0 loops=1)
 Planning time: 0.373 ms
 Execution time: 0.069 ms
(12 rows)

अच्छी खबर है, हमने जो एकल पंक्ति डाली है वह 2018 तालिका में आ गई है, जहां वह है। लेकिन जैसा कि हम देख सकते हैं, क्वेरी दिनांक कॉलम का उपयोग करके कहां क्लॉज निर्दिष्ट नहीं करती है, इसलिए सब कुछ लाने के लिए, क्वेरी प्लानर और निष्पादन ने प्रत्येक तालिका पर अनुक्रमिक स्कैन किया।

इसके बाद, जहां क्लॉज का उपयोग करके परीक्षण करते हैं।

severalnines=# EXPLAIN ANALYZE SELECT * FROM data_log WHERE date >= '2018-08-01' AND date < '2018-09-01';
                                                                   QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------
 Append  (cost=0.00..2.03 rows=2 width=44) (actual time=0.013..0.014 rows=1 loops=1)
   ->  Seq Scan on data_log  (cost=0.00..1.00 rows=1 width=44) (actual time=0.007..0.007 rows=0 loops=1)
         Filter: ((date >= '2018-08-01 00:00:00'::timestamp without time zone) AND (date < '2018-09-01 00:00:00'::timestamp without time zone))
   ->  Seq Scan on data_log_2018  (cost=0.00..1.03 rows=1 width=44) (actual time=0.006..0.006 rows=1 loops=1)
         Filter: ((date >= '2018-08-01 00:00:00'::timestamp without time zone) AND (date < '2018-09-01 00:00:00'::timestamp without time zone))
 Planning time: 0.591 ms
 Execution time: 0.041 ms
(7 rows)

यहां हम देख सकते हैं कि क्वेरी प्लानर और निष्पादन ने 2018 के लिए दो टेबल, पैरेंट और चाइल्ड टेबल पर क्रमिक स्कैन किया। वर्ष 2013 - 2020 के लिए चाइल्ड टेबल हैं, लेकिन 2018 के अलावा अन्य को कभी एक्सेस नहीं किया गया क्योंकि जहां क्लॉज है। केवल 2018 के भीतर की एक सीमा है। क्वेरी प्लानर ने अन्य सभी तालिकाओं को खारिज कर दिया क्योंकि CHECK CONSTRAINT डेटा को उन तालिकाओं में मौजूद होना असंभव मानता है।

सख्त ORM टूल या सम्मिलित पंक्ति सत्यापन के साथ कार्य विभाजन

जैसा कि पहले उल्लेख किया गया है, हमने जो उदाहरण बनाया है वह एक 'INSERT 0 0' देता है, भले ही हमने एक पंक्ति डाली हो। यदि इन विभाजित तालिकाओं में डेटा डालने वाले अनुप्रयोग यह सत्यापित करने पर निर्भर करते हैं कि डाली गई पंक्तियाँ सही हैं, तो ये विफल हो जाएंगी। एक सुधार है, लेकिन यह विभाजित तालिका में जटिलता की एक और परत जोड़ता है, इसलिए इसे अनदेखा किया जा सकता है यदि यह परिदृश्य विभाजित तालिका का उपयोग करने वाले अनुप्रयोगों के लिए कोई समस्या नहीं है।

पेरेंट टेबल के बजाय व्यू का उपयोग करना।

इस समस्या का समाधान एक ऐसा दृश्य बनाना है जो पैरेंट तालिका को क्वेरी करता है, और INSERT कथनों को दृश्य में निर्देशित करता है। किसी दृश्य में सम्मिलित करना पागल लग सकता है, लेकिन दृश्य पर ट्रिगर यहीं से आता है।

severalnines=# CREATE VIEW data_log_view AS 
 SELECT data_log.data_log_sid,
     data_log.date,
     data_log.event_details
    FROM data_log;
CREATE VIEW

severalnines=# ALTER VIEW data_log_view ALTER COLUMN data_log_sid SET default nextval('data_log_data_log_sid_seq'::regclass);
ALTER VIEW

इस दृश्य को क्वेरी करना मुख्य तालिका को क्वेरी करने जैसा लगेगा, और WHERE क्लॉज़ के साथ-साथ JOINS अपेक्षा के अनुरूप काम करेंगे।

विशिष्ट कार्य और ट्रिगर देखें

हमारे द्वारा पहले परिभाषित फ़ंक्शन और ट्रिगर का उपयोग करने के बजाय, वे दोनों थोड़े अलग होंगे। बोल्ड में परिवर्तन।

CREATE OR REPLACE FUNCTION public.insert_trigger_view()
 RETURNS trigger
 LANGUAGE plpgsql
AS $function$
BEGIN
    IF NEW.date >= '2018-01-01' AND NEW.date < '2019-01-01' THEN
        INSERT INTO part.data_log_2018 VALUES (NEW.*);
        RETURN NEW;

    ELSIF NEW.date >= '2019-01-01' AND NEW.date < '2020-01-01' THEN
        INSERT INTO part.data_log_2019 VALUES (NEW.*);
        RETURN NEW;

    END IF;
END;
$function$;

severalnines=# CREATE TRIGGER insert_trigger INSTEAD OF INSERT ON data_log_view FOR EACH ROW EXECUTE PROCEDURE insert_trigger_view();

"INSTEAD OF" परिभाषा दृश्य पर सम्मिलित करें आदेश लेती है (जो वैसे भी काम नहीं करेगा), और इसके बजाय फ़ंक्शन निष्पादित करता है। हमारे द्वारा परिभाषित फ़ंक्शन में चाइल्ड टेबल में डालने के बाद 'रिटर्न न्यू' करने की एक बहुत ही विशिष्ट आवश्यकता है। इसके बिना (या ऐसा करने से जैसा हमने पहले 'रिटर्न न्यूल' के साथ किया था) परिणाम 'INSERT 0 1' के बजाय 'INSERT 0 0' में होगा जैसा कि हम उम्मीद करेंगे।

उदाहरण:

severalnines=# INSERT INTO data_log_view (date, event_details) VALUES ('2018-08-20 18:12:48', 'First insert on the view');
INSERT 0 1

severalnines=# EXPLAIN ANALYZE SELECT * FROM data_log_view WHERE date >= '2018-08-01' AND date < '2018-09-01';
                                                                   QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------
 Append  (cost=0.00..2.03 rows=2 width=44) (actual time=0.015..0.017 rows=2 loops=1)
   ->  Seq Scan on data_log  (cost=0.00..1.00 rows=1 width=44) (actual time=0.009..0.009 rows=0 loops=1)
         Filter: ((date >= '2018-08-01 00:00:00'::timestamp without time zone) AND (date < '2018-09-01 00:00:00'::timestamp without time zone))
   ->  Seq Scan on data_log_2018  (cost=0.00..1.03 rows=1 width=44) (actual time=0.006..0.007 rows=2 loops=1)
         Filter: ((date >= '2018-08-01 00:00:00'::timestamp without time zone) AND (date < '2018-09-01 00:00:00'::timestamp without time zone))
 Planning time: 0.633 ms
 Execution time: 0.048 ms
(7 rows)

severalnines=# SELECT * FROM data_log_view WHERE date >= '2018-08-01' AND date < '2018-09-01';
 data_log_sid |        date         |      event_details
--------------+---------------------+--------------------------
            1 | 2018-08-20 15:22:14 | First insert
            2 | 2018-08-20 18:12:48 | First insert on the view
(2 rows)

सम्मिलित 'पंक्ति गणना' के सही होने के लिए आवेदन परीक्षण इस सुधार को अपेक्षित रूप से काम करने के लिए पाएगा। इस उदाहरण में, हमने अपने दृश्य और संग्रहीत कार्यविधि में _view को जोड़ा है, लेकिन यदि तालिका को बिना किसी उपयोगकर्ता को जाने/एप्लिकेशन परिवर्तन के बिना विभाजित करने के लिए वांछित होना है, तो हम मूल तालिका का नाम बदलकर data_log_parent करेंगे, और पुराने द्वारा दृश्य को कॉल करेंगे पैरेंट टेबल का नाम।

पंक्ति को अपडेट करना और विभाजित कॉलम के मान को बदलना

एक बात का ध्यान रखना चाहिए कि यदि विभाजित तालिका में डेटा पर एक अद्यतन कर रहा है, और स्तंभ के मान को किसी ऐसी चीज़ में बदलने की अनुमति नहीं है जो बाधा द्वारा अनुमत है, तो एक त्रुटि होगी। यदि इस प्रकार का अद्यतन कभी नहीं होगा, तो इसे अनदेखा किया जा सकता है, लेकिन यदि यह एक संभावना है, तो अद्यतन प्रक्रियाओं के लिए एक नया ट्रिगर लिखा जाना चाहिए जो पुराने बाल विभाजन से पंक्ति को प्रभावी ढंग से हटा देगा, और एक नया सम्मिलित करेगा नया लक्ष्य बाल विभाजन।

भविष्य के विभाजन बनाना

भविष्य के विभाजन बनाना कुछ अलग तरीकों से किया जा सकता है, जिनमें से प्रत्येक के अपने फायदे और नुकसान हैं।

भविष्य के विभाजन निर्माता

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

स्वचालित विभाजन निर्माता

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

विभाजन छोड़ना

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

severalnines=# DROP TABLE part.data_log_2007;
DROP TABLE

यह 'DELETE' कथन की तुलना में बहुत तेज़ और अधिक कुशल है, क्योंकि इसका परिणाम किसी भी मृत ट्यूपल्स को वैक्यूम से साफ करने के लिए नहीं होता है।

नोट:यदि विभाजन सेटअप से तालिकाओं को हटा रहे हैं, तो ट्रिगर फ़ंक्शन में कोड को भी बदल दिया जाना चाहिए, न कि तिथि को गिराए गए तालिका पर निर्देशित करना।

विभाजन से पहले जानने योग्य बातें

विभाजन तालिकाएँ प्रदर्शन में भारी सुधार की पेशकश कर सकती हैं, लेकिन यह इसे बदतर भी बना सकती हैं। उत्पादन सर्वरों को आगे बढ़ाने से पहले, डेटा स्थिरता, प्रदर्शन गति, सब कुछ के लिए विभाजन रणनीति का बड़े पैमाने पर परीक्षण किया जाना चाहिए। तालिका के विभाजन में कुछ गतिशील भाग होते हैं, यह सुनिश्चित करने के लिए सभी का परीक्षण किया जाना चाहिए कि कोई समस्या नहीं है।

जब विभाजनों की संख्या तय करने की बात आती है, तो यह सुझाव दिया जाता है कि चाइल्ड टेबल की संख्या को 1000 टेबल के नीचे रखें, और यदि संभव हो तो इससे भी कम। एक बार जब चाइल्ड टेबल की संख्या ~1000 से ऊपर हो जाती है, तो प्रदर्शन में गिरावट आने लगती है क्योंकि क्वेरी प्लानर को केवल क्वेरी प्लान बनाने में अधिक समय लगता है। यह अनसुना नहीं है कि एक क्वेरी योजना में कई सेकंड लगते हैं, जबकि वास्तविक निष्पादन में केवल कुछ मिलीसेकंड लगते हैं। यदि एक मिनट में हज़ारों प्रश्नों को पूरा करने पर, कुछ सेकंड में एप्लिकेशन रुक सकते हैं।

Plpgsql ट्रिगर संग्रहीत कार्यविधियाँ भी जटिल हो सकती हैं, और यदि बहुत जटिल हैं, तो प्रदर्शन को भी धीमा कर सकती हैं। तालिका में डाली गई प्रत्येक पंक्ति के लिए संग्रहीत कार्यविधि एक बार निष्पादित की जाती है। यदि यह प्रत्येक पंक्ति के लिए बहुत अधिक प्रसंस्करण कर रहा है, तो प्रविष्टियां बहुत धीमी हो सकती हैं। प्रदर्शन परीक्षण यह सुनिश्चित करेगा कि यह अभी भी स्वीकार्य सीमा में है।

क्रिएटिव बनें

PostgreSQL में विभाजन तालिकाएँ आवश्यकतानुसार उन्नत हो सकती हैं। दिनांक कॉलम के बजाय, तालिकाओं को 'देश' कॉलम पर विभाजित किया जा सकता है, प्रत्येक देश के लिए एक तालिका के साथ। विभाजन कई कॉलमों पर किया जा सकता है, जैसे 'तारीख' और 'देश' कॉलम दोनों। यह इन्सर्ट को संभालने वाली संग्रहित प्रक्रिया को अधिक जटिल बना देगा, लेकिन यह 100% संभव है।

याद रखें, विभाजन के साथ लक्ष्य बहुत बड़ी तालिकाओं को छोटे में तोड़ना है, और इसे एक अच्छी तरह से सोचे-समझे तरीके से करना है ताकि क्वेरी प्लानर को डेटा को बड़ी मूल तालिका की तुलना में तेज़ी से एक्सेस करने की अनुमति मिल सके।

घोषणात्मक विभाजन

PostgreSQL 10 और बाद में, एक नई विभाजन सुविधा 'घोषणात्मक विभाजन' पेश की गई थी। यह विभाजनों को स्थापित करने का एक आसान तरीका है, हालाँकि इसकी कुछ सीमाएँ हैं, यदि सीमाएँ स्वीकार्य हैं, तो यह संभवतः मैन्युअल विभाजन सेटअप की तुलना में तेज़ प्रदर्शन करेगा, लेकिन बहुत अधिक मात्रा में परीक्षण इसे सत्यापित करेगा।

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

घोषणात्मक विभाजन सीमाएं

PostgreSQL दस्तावेज़ PostgreSQL 10 में इस प्रकार के विभाजन के साथ सभी सीमाओं को संबोधित करता है, लेकिन आधिकारिक पोस्टग्रेएसक्यूएल विकी पर एक महान अवलोकन पाया जा सकता है जो कि पढ़ने में आसान प्रारूप में सीमाओं को सूचीबद्ध करता है, साथ ही यह भी नोट करता है कि कौन सा तय किया गया है आगामी PostgreSQL 11.

समुदाय से पूछें

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

  • आईआरसी
    फ़्रीनोड का एक बहुत ही सक्रिय चैनल है जिसे #postgres कहा जाता है, जहां उपयोगकर्ता अवधारणाओं को समझने, त्रुटियों को ठीक करने, या अन्य संसाधन खोजने में एक-दूसरे की सहायता करते हैं।
  • मेलिंग सूचियां
    PostgreSQL में कुछ मेलिंग सूचियां हैं जिन्हें जोड़ा जा सकता है। लंबे फॉर्म वाले प्रश्न/मुद्दे यहां भेजे जा सकते हैं, और किसी भी समय आईआरसी की तुलना में कई अधिक लोगों तक पहुंच सकते हैं। सूचियाँ PostgreSQL वेबसाइट पर पाई जा सकती हैं, और सूचियाँ pgsql-General या pgsql-admin अच्छे संसाधन हैं।

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. row_to_json . के साथ पुनरावर्ती क्वेरी को पोस्टग्रेज करता है

  2. PostgreSQL के साथ पिछली जगहों को ट्रिम करें

  3. डीबी अनुप्रयोगों के लिए ऑडिट ट्रेल/परिवर्तन इतिहास छोड़ने के लिए प्रभावी रणनीति?

  4. मैं एक अलग स्कीमा के साथ डेटाबेस को पुनर्स्थापित करना चाहता हूं

  5. PostgreSQL एक कस्टम डेटा प्रकार के साथ एक फ़ंक्शन लौटाता है