विभाजन क्या है?
विभाजन बड़ी तालिकाओं को छोटे टुकड़ों में विभाजित करता है, जो क्वेरी प्रदर्शन को बढ़ाने में मदद करता है, रखरखाव कार्यों को आसान बनाता है, डेटा संग्रह की दक्षता में सुधार करता है, और तेज़ डेटाबेस बैकअप। आप हमारे ब्लॉग "ए गाइड टू पार्टिशनिंग डेटा इन पोस्टग्रेएसक्यूएल" में PostgreSQL विभाजन के बारे में अधिक पढ़ सकते हैं।
PostgreSQL 11 की हालिया रिलीज़ के साथ बहुत सारी नई अद्भुत विभाजन सुविधाएँ हैं। इन नई विभाजन सुविधाओं का विवरण कुछ कोड उदाहरणों के साथ इस ब्लॉग में शामिल किया जाएगा।
विभाजन कुंजियों को अपडेट करना
PostgreSQL 11 से पहले, विभाजन कुंजी के मान को बदलने वाले अपडेट स्टेटमेंट को प्रतिबंधित किया गया था और इसकी अनुमति नहीं थी। यह अब नए संस्करण में संभव है। अद्यतन विवरण विभाजन कुंजी के मान को बदल सकता है; यह वास्तव में पंक्तियों को सही विभाजन तालिका में ले जाता है। हुड के तहत यह मूल रूप से पुराने विभाजन से DELETE और नए विभाजन में INSERT निष्पादित करता है ( DELETE + INSERT)।
ठीक है, आइए इसका परीक्षण करें। एक तालिका बनाएं और सत्यापित करें कि विभाजन कुंजी पर अद्यतन कैसे काम करता है।
CREATE TABLE customers(cust_id bigint NOT NULL,cust_name varchar(32) NOT NULL,cust_address text,
cust_country text)PARTITION BY LIST(cust_country);
CREATE TABLE customer_ind PARTITION OF customers FOR VALUES IN ('ind');
CREATE TABLE customer_jap PARTITION OF customers FOR VALUES IN ('jap');
CREATE TABLE customers_def PARTITION OF customers DEFAULT;
severalnines_v11=# INSERT INTO customers VALUES (2039,'Puja','Hyderabad','ind');
INSERT 0 1
severalnines_v11=# SELECT * FROM customer_ind;
cust_id | cust_name | cust_address | cust_country
2039 | Puja | Hyderabad | ind
(1 row)
severalnines_v11=# UPDATE customers SET cust_country ='jap' WHERE cust_id=2039;
UPDATE 1
-- it moved the row to correct partition table.
severalnines_v11=# SELECT * FROM customer_ind;
cust_id | cust_name | cust_address | cust_country
---------+-----------+--------------+--------------
(0 rows)
severalnines_v11=# SELECT * FROM customer_jap;
cust_id | cust_name | cust_address | cust_country
---------+-----------+--------------+--------------
2039 | Puja | Hyderabad | jap
(1 row)
सावधानी:यदि कोई डिफ़ॉल्ट विभाजन तालिका नहीं है और अद्यतन मान किसी चाइल्ड तालिका में विभाजन मानदंड से मेल नहीं खाते हैं, तो अद्यतन त्रुटि होगी।
severalnines_v11=# UPDATE customers1 SET cust_country ='ypp' WHERE cust_id=2039;
2018-11-21 00:13:54.901 IST [1479] ERROR: no partition of relation "customers1" found for row
2018-11-21 00:13:54.901 IST [1479] DETAIL: Partition key of the failing row contains (cust_country) = (ypp).
2018-11-21 00:13:54.901 IST [1479] STATEMENT: UPDATE customers1 SET cust_country ='ypp' WHERE cust_id=2039;
ERROR: no partition of relation "customers1" found for row
DETAIL: Partition key of the failing row contains (cust_country) = (ypp).
[ -- the value of cust_country was not mapped to any part table so it failed]
डिफ़ॉल्ट विभाजन बनाना
PostgreSQL 11 DEFAULT पार्टिशन फीचर टुपल्स को स्टोर करता है जो किसी अन्य पार्टीशन के लिए मैप नहीं करते हैं। PostgreSQL 11 से पहले, ये पंक्तियाँ त्रुटिपूर्ण होंगी। एक पंक्ति जो किसी भी विभाजन तालिका में मैप नहीं की गई है, उसे डिफ़ॉल्ट विभाजन में सम्मिलित किया जाएगा।
लैब उदाहरण:`यूएसए` देश कोड नीचे विभाजन तालिका में परिभाषित नहीं किया गया था, लेकिन फिर भी यह डिफ़ॉल्ट तालिका में सफलतापूर्वक सम्मिलित हो जाता है।
CREATE TABLE customers_def PARTITION OF customers DEFAULT;
severalnines_v11=# INSERT INTO customers VALUES (4499,'Tony','Arizona','USA');
INSERT 0 1
severalnines_v11=# select * FROM customers_def;
cust_id | cust_name | cust_address | cust_country
---------+-----------+--------------+--------------
4499 | Tony | Arizona | USA
सावधानी की बात:यदि वह विभाजन मान डिफ़ॉल्ट तालिका में मौजूद है, तो डिफ़ॉल्ट विभाजन किसी भी नए विभाजन को जोड़ देगा। इस मामले में `यूएसए` डिफ़ॉल्ट विभाजन में मौजूद था इसलिए यह नीचे की तरह काम नहीं करेगा।
severalnines_v11=# CREATE TABLE customer_usa PARTITION OF customers FOR VALUES IN ('USA');
2018-11-21 00:46:34.890 IST [1526] ERROR: updated partition constraint for default partition "customers_def" would be violated by some row
2018-11-21 00:46:34.890 IST [1526] STATEMENT: CREATE TABLE customer_usa PARTITION OF customers FOR VALUES IN ('USA');ERROR: updated partition constraint for default partition "customers_def" would be violated by some row
severalnines_v11=#
Resolution - You need to move/remove those rows from Default table, then it will then let you create new part table like below.
severalnines_v11=# DELETE FROM customers_def WHERE cust_country in ('USA'); DELETE 1
severalnines_v11=# CREATE TABLE customer_usa PARTITION OF customers FOR VALUES IN ('USA');
CREATE TABLE
severalnines_v11=#
Nudgets :
HASH विभाजन तालिका के लिए DEFAULT विभाजन निर्दिष्ट नहीं किया जा सकता है। विभाजन तालिका के लिए एक से अधिक डिफ़ॉल्ट तालिका नहीं हो सकती है।
हैश विभाजन
यह एक नया विभाजन तंत्र है, यदि आप किसी श्रेणी या सूची विभाजन पर निर्णय नहीं ले सकते हैं (जैसा कि आप सुनिश्चित नहीं हैं कि बाल्टी कितनी बड़ी होगी)। हैश विभाजन इस डेटा वितरण समस्या को हल करता है।
प्रत्येक विभाजन के लिए एक मापांक और एक शेष निर्दिष्ट करके तालिका को विभाजित किया जाता है। प्रत्येक विभाजन उन पंक्तियों को धारण करेगा जिनके लिए निर्दिष्ट मापांक द्वारा विभाजित विभाजन कुंजी का हैश मान निर्दिष्ट शेष उत्पन्न करेगा। HASH फ़ंक्शन सुनिश्चित करता है कि पंक्तियों को सभी विभाजन तालिका में समान रूप से वितरित किया जाएगा।
आरंभ करने के लिए, आपको यह तय करने की आवश्यकता है कि विभाजन तालिका की कितनी संख्या की आवश्यकता है और, तदनुसार, मापांक और शेष को परिभाषित किया जा सकता है; यदि मापांक 4 होगा, तो शेष केवल [0-3] से हो सकता है।
[मापांक - तालिकाओं की संख्या | शेष - शेष का कौन सा मान किस बकेट में जाता है ]
हैश पार्टीशन कैसे सेटअप करें
-- hash partition
CREATE TABLE part_hash_test (x int, y text) PARTITION BY hash (x);
-- create child partitions
CREATE TABLE part_hash_test_0 PARTITION OF part_hash_test FOR VALUES WITH (MODULUS 4, REMAINDER 0);
CREATE TABLE part_hash_test_1 PARTITION OF part_hash_test FOR VALUES WITH (MODULUS 4, REMAINDER 1);
CREATE TABLE part_hash_test_2 PARTITION OF part_hash_test FOR VALUES WITH (MODULUS 4, REMAINDER 2);
CREATE TABLE part_hash_test_3 PARTITION OF part_hash_test FOR VALUES WITH (MODULUS 4, REMAINDER 3);
पैरेंट टेबल में 50k रिकॉर्ड डालें:
severalnines_v11=# INSERT INTO part_hash_test SELECT generate_series(0,50000);
INSERT 0 50001
और देखें कि इसने चाइल्ड टेबल में रिकॉर्ड को समान रूप से कैसे वितरित किया ...
severalnines_v11=# SELECT count(1),tableoid::regclass FROM part_hash_test GROUP by 2 order by 2 ;
count | tableoid
-------+------------------
12537 | part_hash_test_0
12473 | part_hash_test_1
12509 | part_hash_test_2
12482 | part_hash_test_3
(4 rows)
हम पहले `मॉड्यूलस` द्वारा निर्दिष्ट विभाजनों की संख्या को नहीं बदल सकते हैं, इसलिए आपको विभाजन तालिकाओं की संख्या के लिए आवश्यकताओं से पहले अच्छी तरह से योजना बनाने की आवश्यकता है।
जब आप किसी भिन्न शेष के साथ एक नया विभाजन जोड़ने का प्रयास करेंगे तो यह त्रुटिपूर्ण हो जाएगा।
severalnines_v11=# CREATE TABLE part_hash_test_5 PARTITION OF part_hash_test FOR VALUES
WITH (MODULUS 4, REMAINDER 5);severalnines_v11-#
2018-11-21 01:51:28.966 IST [1675] ERROR: remainder for hash partition must be less than modulus
2018-11-21 01:51:28.966 IST [1675] STATEMENT: CREATE TABLE part_hash_test_5 PARTITION OF part_hash_test FOR VALUES WITH (MODULUS 4, REMAINDER 5);
हैश विभाजन किसी भी डेटा प्रकार पर काम कर सकता है और यह यूयूआईडी प्रकार के लिए भी काम कर सकता है। यह हमेशा अनुशंसा की जाती है कि तालिकाओं की संख्या 2 की शक्ति होनी चाहिए, और तालिका बनाते समय समान मापांक का उपयोग करना भी अनिवार्य नहीं है; यह बाद में आवश्यकतानुसार विभाजन तालिका बनाने में मदद करेगा।
यह कार्यान्वयन वैक्यूम को भी तेज़ बना देगा और विभाजन के अनुसार जुड़ने को सक्षम कर सकता है।
विदेशी कुंजी के लिए समर्थन
PostgreSQL 11 से पहले, विभाजन तालिका में विदेशी कुंजी समर्थित नहीं थी। विभाजन तालिका में विदेशी कुंजी अभी और नीचे संभव है...
severalnines_v11=# CREATE TABLE customers2 ( cust_id integer PRIMARY KEY );
CREATE TABLE
severalnines_v11=# CREATE TABLE account (
ac_date date NOT NULL,
cust_id integer REFERENCES customers2(cust_id),
amount INTEGER NOT NULL) PARTITION BY RANGE (ac_date);
CREATE TABLE
चाइल्ड टेबल पर ऑटो इंडेक्स क्रिएशन
PostgreSQL के पिछले संस्करणों में यह प्रत्येक विभाजन तालिका पर एक अनुक्रमणिका बनाने का एक मैन्युअल प्रयास था। PostgreSQL संस्करण 11 में, यह उपयोगकर्ताओं के लिए काफी सुविधाजनक है। एक बार जब इंडेक्स मास्टर टेबल पर बन जाता है, तो यह स्वचालित रूप से सभी मौजूदा चाइल्ड पार्टीशन पर समान कॉन्फ़िगरेशन के साथ इंडेक्स बनाएगा और भविष्य के किसी भी पार्टीशन टेबल का भी ध्यान रखेगा।
मास्टर टेबल पर इंडेक्स बनाया गया
severalnines_v11=# CREATE index idx_name ON customers(cust_name);
CREATE INDEX
यह स्वचालित रूप से नीचे के रूप में सभी चाइल्ड टेबल पर इंडेक्स बनाता है। (सूची तालिका के साथ सत्यापित करें)
severalnines_v11=# SELECT tablename,indexname,indexdef FROM pg_indexes WHERE tablename ilike '%customer_%';
tablename | indexname | indexdef
---------------+-----------------------------+------------------------------------------------------------------------------------------
customer_ind | customer_ind_cust_name_idx | CREATE INDEX customer_ind_cust_name_idx ON public.customer_ind USING btree (cust_name)
customer_jap | customer_jap_cust_name_idx | CREATE INDEX customer_jap_cust_name_idx ON public.customer_jap USING btree (cust_name)
customer_usa | customer_usa_cust_name_idx | CREATE INDEX customer_usa_cust_name_idx ON public.customer_usa USING btree (cust_name)
customers_def | customers_def_cust_name_idx | CREATE INDEX customers_def_cust_name_idx ON public.customers_def USING btree (cust_name)
(4 rows)
इंडेक्स केवल मास्टर टेबल पर बनाया जा सकता है, यह चाइल्ड टेबल पर नहीं हो सकता है। स्वचालित रूप से उत्पन्न अनुक्रमणिका को अलग-अलग नहीं हटाया जा सकता।
चाइल्ड टेबल पर ऑटो ट्रिगर क्रिएशन
एक बार मास्टर टेबल पर ट्रिगर बन जाने के बाद, यह स्वचालित रूप से सभी चाइल्ड टेबल पर ट्रिगर बना देगा (यह व्यवहार इंडेक्स के लिए देखे गए व्यवहार के समान है)।
अद्वितीय अनुक्रमणिका बनाने में सक्षम
संस्करण 11 में अद्वितीय अनुक्रमणिका को मास्टर तालिका में जोड़ा जा सकता है जो सभी मौजूदा चाइल्ड टेबल और भविष्य के विभाजन तालिकाओं पर अद्वितीय बाधा उत्पन्न करेगा।
आइए अद्वितीय बाधाओं के साथ एक मास्टर टेबल बनाएं।
CREATE TABLE uniq_customers( cust_id bigint NOT NULL, cust_name varchar(32) NOT NULL, cust_address text, cust_country text,cust_email text, unique(cust_email,cust_id,cust_country) )PARTITION BY LIST(cust_country);
चाइल्ड टेबल पर स्वचालित रूप से नीचे की तरह अद्वितीय बाधा बनाई गई है।
severalnines_v11=# SELECT table_name,constraint_name,constraint_type FROM information_schema.table_constraints WHERE table_name ilike '%uniq%' AND constraint_type = 'UNIQUE';
table_name | constraint_name | constraint_type
-------------------+-------------------------------------------------------+-----------------
uniq_customers | uniq_customers_cust_email_cust_id_cust_country_key | UNIQUE
uniq_customer_ind | uniq_customer_ind_cust_email_cust_id_cust_country_key | UNIQUE
(2 rows)
सावधानी:मूल तालिका पर एक अद्वितीय बाधा वास्तव में संपूर्ण विभाजन पदानुक्रम में विशिष्टता की गारंटी नहीं देती है। यह वैश्विक बाधा नहीं है, यह केवल स्थानीय है।
आज श्वेतपत्र डाउनलोड करें क्लस्टरकंट्रोल के साथ पोस्टग्रेएसक्यूएल प्रबंधन और स्वचालन इस बारे में जानें कि पोस्टग्रेएसक्यूएल को तैनात करने, मॉनिटर करने, प्रबंधित करने और स्केल करने के लिए आपको क्या जानना चाहिए। श्वेतपत्र डाउनलोड करेंतेज़ क्वेरी प्रदर्शन
डायनामिक पार्टिशन प्रूनिंग
PostgreSQL 11 में, बाइनरी सर्च आवश्यक चाइल्ड टेबल की तेजी से पहचान करने में सक्षम बनाता है चाहे वह LIST हो या RANGE विभाजन। हैशिंग फंक्शन HASH पार्टीशन के लिए मैचिंग पार्टिशन ढूंढता है। यह वास्तव में उन विभाजन तालिका (तालिकाओं) को गतिशील रूप से समाप्त करता है जिनकी आवश्यकता नहीं है और क्वेरी प्रदर्शन को बढ़ा देता है।
गतिशील विभाजन प्रूनिंग को `enable_partition_pruning` पैरामीटर द्वारा नियंत्रित किया जा सकता है।
severalnines_v11=# show enable_partition_pruning;
enable_partition_pruning
--------------------------
off
(1 row)
severalnines_v11=# EXPLAIN SELECT * from customers where cust_country = 'ind';
QUERY PLAN
---------------------------------------------------------------------
Append (cost=0.00..18.54 rows=5 width=154)
-> Seq Scan on customer_ind (cost=0.00..1.01 rows=1 width=154)
Filter: (cust_country = 'ind'::text)
-> Seq Scan on customer_jap (cost=0.00..1.00 rows=1 width=154)
Filter: (cust_country = 'ind'::text)
-> Seq Scan on customer_usa (cost=0.00..15.50 rows=2 width=154)
Filter: (cust_country = 'ind'::text)
-> Seq Scan on customers_def (cost=0.00..1.00 rows=1 width=154)
Filter: (cust_country = 'ind'::text)
(9 rows)
Enabled the parameter to ON.
severalnines_v11=# set enable_partition_pruning TO on;
SET
severalnines_v11=# EXPLAIN SELECT * from customers where cust_country = 'ind';
QUERY PLAN
--------------------------------------------------------------------
Append (cost=0.00..1.02 rows=1 width=154)
-> Seq Scan on customer_ind (cost=0.00..1.01 rows=1 width=154)
Filter: (cust_country = 'ind'::text)
(3 rows)
अन्य भयानक कार्यान्वयन इस प्रकार है।
निष्पादन-समय विभाजन प्रूनिंग
11 से पहले के पोस्टग्रेएसक्यूएल संस्करणों में, विभाजन छंटाई केवल योजना समय पर ही हो सकती है; प्लानर को विभाजन कुंजी के मान की आवश्यकता होती है सही विभाजन की पहचान करने के लिए। यह व्यवहार PostgreSQL 11 में तय किया गया है, क्योंकि निष्पादन समय योजनाकार को पता होगा कि किस मूल्य की आपूर्ति की जा रही है और उस विभाजन के आधार पर चयन/उन्मूलन संभव है और बहुत तेजी से चलेगा। उपयोग का मामला एक क्वेरी हो सकता है जो पैरामीटर (तैयार कथन) या सबक्वायरी का उपयोग करता है जो पैरामीटर के रूप में मान प्रदान करता है।
Example : cus_country is partition key and getting value from subquery
severalnines_v11=# explain analyze select * from customers WHERE cust_country = (select cust_count_x FROM test_execution_prun1);
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------
Append (cost=23.60..42.14 rows=5 width=154) (actual time=0.019..0.020 rows=0 loops=1)
InitPlan 1 (returns $0)
-> Seq Scan on test_execution_prun1 (cost=0.00..23.60 rows=1360 width=32) (actual time=0.006..0.007 rows=1 loops=1)
-> Seq Scan on customer_ind (cost=0.00..1.01 rows=1 width=154) (never executed)
Filter: (cust_country = $0)
-> Seq Scan on customer_jap (cost=0.00..1.00 rows=1 width=154) (never executed)
Filter: (cust_country = $0)
-> Seq Scan on customer_usa (cost=0.00..15.50 rows=2 width=154) (never executed)
Filter: (cust_country = $0)
-> Seq Scan on customers_def (cost=0.00..1.00 rows=1 width=154) (actual time=0.003..0.003 rows=0 loops=1)
Filter: (cust_country = $0)
Planning Time: 0.237 ms
Execution Time: 0.057 ms
(13 rows)
उपरोक्त व्याख्या योजना में, हम देख सकते हैं, निष्पादन के समय, फ्लाई पर योजनाकार ने पैरामीटर मान के आधार पर सही विभाजन तालिका की पहचान की, और बहुत तेजी से दौड़ा और अन्य विभाजन तालिका पर स्कैन/लूप पर समय नहीं बिताया (देखें कभी नहीं उपरोक्त व्याख्या योजना में निष्पादित अनुभाग)। यह बहुत शक्तिशाली है और विभाजन में प्रदर्शन वृद्धि के एक नए युग की शुरुआत की।
विभाजन के आधार पर सकल
पैरामीटर:enable_partitionwise_aggregate
यदि विभाजन कुंजी समूहीकरण कुंजी से मेल खाती है, तो प्रत्येक विभाजन एक बार में सभी विभाजनों को स्कैन करने के बजाय समूहों का एक असतत सेट तैयार करेगा। यह प्रत्येक विभाजन के लिए समानांतर समुच्चय करेगा और अंतिम परिणाम के दौरान यह सभी परिणामों को जोड़ देगा।
severalnines_v11=# explain SELECT count(1),cust_country FROM customers GROUP BY 2;
QUERY PLAN
----------------------------------------------------------------------------
HashAggregate (cost=21.84..23.84 rows=200 width=40)
Group Key: customer_ind.cust_country
-> Append (cost=0.00..19.62 rows=443 width=32)
-> Seq Scan on customer_ind (cost=0.00..1.01 rows=1 width=32)
-> Seq Scan on customer_jap (cost=0.00..1.00 rows=1 width=32)
-> Seq Scan on customer_usa (cost=0.00..14.40 rows=440 width=32)
-> Seq Scan on customers_def (cost=0.00..1.00 rows=1 width=32)
(7 rows)
severalnines_v11=# SET enable_partitionwise_aggregate TO on;
SET
severalnines_v11=# explain SELECT count(1),cust_country FROM customers GROUP BY 2;
QUERY PLAN
----------------------------------------------------------------------------
Append (cost=1.01..22.67 rows=203 width=40)
-> HashAggregate (cost=1.01..1.02 rows=1 width=40)
Group Key: customer_ind.cust_country
-> Seq Scan on customer_ind (cost=0.00..1.01 rows=1 width=32)
-> HashAggregate (cost=1.00..1.01 rows=1 width=40)
Group Key: customer_jap.cust_country
-> Seq Scan on customer_jap (cost=0.00..1.00 rows=1 width=32)
-> HashAggregate (cost=16.60..18.60 rows=200 width=40)
Group Key: customer_usa.cust_country
-> Seq Scan on customer_usa (cost=0.00..14.40 rows=440 width=32)
-> HashAggregate (cost=1.00..1.01 rows=1 width=40)
Group Key: customers_def.cust_country
-> Seq Scan on customers_def (cost=0.00..1.00 rows=1 width=32)
(13 rows)
यह निश्चित रूप से तेज़ है क्योंकि इसमें समानांतर एकत्रीकरण प्रसंस्करण और प्रति विभाजन स्कैनिंग शामिल है।
सभी पैरेंट पार्टीशन टेबल को जानने के लिए कैटलॉग क्वेरी का उपयोग किया जा सकता है।
SELECT relname FROM pg_class WHERE oid in (select partrelid FROM pg_partitioned_table);
संक्षिप्त विभाजन फ़ीचर मैट्रिक्स
विभाजन सुविधाएँ | <थ>v11 <थ>v10||
---|---|---|
डिफ़ॉल्ट विभाजन | हां | नहीं |
विदेशी तालिका विरासत | हां | नहीं |
हैश कुंजी द्वारा विभाजन | हां | नहीं |
पीके और एफके के लिए समर्थन | हां | नहीं |
विभाजन कुंजी पर अद्यतन करें | हां | नहीं |
सीटी पर ऑटोमेटेड इनेक्स | हां | नहीं |
सीटी पर स्वचालित ट्रिगर | हां | नहीं |
निष्पादन समय विभाजन छंटाई | हां | नहीं |
विभाजन वार शामिल हों | हां | नहीं |
डायनामिक पार्टीशन प्रून | हां | नहीं |
आगे क्या?
विभाजन प्रदर्शन
यह अब PostgreSQL समुदाय में सबसे सक्रिय कार्य क्षेत्रों में से एक है। PostgreSQL संस्करण 12 को विभाजन स्थान में और भी अधिक प्रदर्शन सुधारों के साथ पैक किया जाएगा। संस्करण 12 के 2019 के नवंबर में रिलीज़ होने की उम्मीद है।