PostgreSQL 11.2 ‘de Table Partitioning Kavramı

Yusuf Kahveci
Trendyol Tech
Published in
4 min readFeb 7, 2020

Bu yazımızda büyük verilere sahip tablolarımızda uyguladığımız partitioning kavramını ele alacağız.

PostgreSQL 10 öncesinde kullanılan partitioning yöntemi çok fazla manuel işlem içermekte ve sıkıntılı bir süreçti. 10 öncesi versiyonlarda partition lara veri aktarmak için trigger kullanıldığını düşünecek olur isek ne kadar manuel ve problemli bir süreç olduğunu tahmin edebilirsiniz.

Partitioning, tabloyu belirli yöntemlere göre parçalamaya denilmektedir. Parçaladığımız ana tabloya master, parçalarına ise child denmektedir.

Avantajları nelerdir ?

  • Sorgu performanslarımızda ciddi derecede artış sağlamakta. (Sorgularımız ilgili partitionda ki datayı çektiğinden tablonun tamamına değilde sadece ilgili partitionda ki datalara dokunarak daha hızlı result dönmekte.)
  • Index maliyeti ve Size ‘ı azalmakta.Sadece ilgili partition ‘a index atarak hem index lerimizin boyutunu küçültüp hem de index fragmantasyon larımızın azalmasına olanak sağlamakta.
  • Bulk operasyonlarımızı daha sağlıklı ve hızlı yönetilebilmekte.

Partition tiplerimiz nelerdir ?

A. LIST :
PARTITION KEY değeri neyse sadece o değerlere ait veriler parçalanır.
Örneğin status alanı ACTIVE, PASIVE olan değerleri içeren tüm satırlar için ayrıca partition oluşturulması için LIST kullanılır.

B. RANGE :
Belirlenen kriterlere göre tablo bölümlenmesi gerçekleşir. Tarih aralığına bölünebileceği gibi belirli objelere göre partition yapılabilir.
Örneğin, belirli tarih aralığı için RANGE kullanılabilir.

C. HASH :
Partition Key’in ait hash değerine göre satır bazlı verilerin partition tablolarına aktarılmasıdır. RANGE ve LIST partition ınıza benzer şekilde oluşturulur.
Partition tablolarının oluşturulması sırasında MODULUS ve REMAINDER kavramları var. MODULUS değeri bizim kaç adet partition tablomuzun olduğunu belirtir ve tüm partition tabloları için sabittir ve
değişmez. REMAINDER değeri HASH partition için kullanılan hash key ‘in, yani tablomuzu bölmek için kullanacağımız sütun, hash değerini REMAINDER’a böler ve kalan değer ne ise o REMAINDER’in bulunduğu partition tablosuna veriyi aktarır.

Örneğin, MODULUS 10 dediğinizde partitioned tablosu 10 adet partition tablosuna sahip demektir ve tüm partition tablolarında sabittir.
REMAINDER 0 dan 9 a kadar tüm değer alır. Böylece tablomuzu hangi sütuna göre böleceksek, o sütunun hash değerini MODULUS değerine böler ve örneğin kalan 3 ise REMAINDER 3 olan partition tablosuna veriyi aktarır.

Şimdi ise demolarımıza geçelim. İlk önce Range Partition örneğinden başlayacağız.

ÖRNEK 1 — Range Partitioning :

İlk etapta demo tablomuzu oluşturalım.

CREATE TABLE satis (
id serial,
satis_adedi int,
satis_tarihi date not null
) PARTITION BY RANGE (satis_tarihi);

Şimdi ise partition larımızı oluşturalım. (Yukarıda demo tablomuzu oluştururken Partition tipimizi ve hangi kolon üzerinden bölünme yapılacağını belirttik. PARTITION BY RANGE (satis_tarihi))

Şimdi Partition larımızı oluşturalım. Burada ay bazlı partition yapacağımızdan tablomuzu son 1 yıl için 12 ye bölümlüyoruz.

CREATE TABLE satislar_2019_01 PARTITION OF satis
FOR VALUES FROM (‘2019–01–01’) TO (‘2019–02–01’);
CREATE TABLE satislar_2019_02 PARTITION OF satis
FOR VALUES FROM (‘2019–02–01’) TO (‘2019–03–01’);
CREATE TABLE satislar_2019_03 PARTITION OF satis
FOR VALUES FROM (‘2019–03–01’) TO (‘2019–04–01’);
CREATE TABLE satislar_2019_04 PARTITION OF satis
FOR VALUES FROM (‘2019–04–01’) TO (‘2019–05–01’);
CREATE TABLE satislar_2019_05 PARTITION OF satis
FOR VALUES FROM (‘2019–05–01’) TO (‘2019–06–01’);
CREATE TABLE satislar_2019_06 PARTITION OF satis
FOR VALUES FROM (‘2019–06–01’) TO (‘2019–07–01’);
CREATE TABLE satislar_2019_07 PARTITION OF satis
FOR VALUES FROM (‘2019–07–01’) TO (‘2019–08–01’);
CREATE TABLE satislar_2019_08 PARTITION OF satis
FOR VALUES FROM (‘2019–08–01’) TO (‘2019–09–01’);
CREATE TABLE satislar_2019_09 PARTITION OF satis
FOR VALUES FROM (‘2019–09–01’) TO (‘2019–10–01’);
CREATE TABLE satislar_2019_10 PARTITION OF satis
FOR VALUES FROM (‘2019–10–01’) TO (‘2019–11–01’);
CREATE TABLE satislar_2019_11 PARTITION OF satis
FOR VALUES FROM (‘2019–11–01’) TO (‘2019–12–01’);
CREATE TABLE satislar_2019_12 PARTITION OF satis
FOR VALUES FROM (‘2019–12–01’) TO (‘2020–01–01’);

Partition işlemimizide tamamladıktan sonra şimdi data girişi yapmadan bir chek edelim.

Aşağıda ki script ile ilgili tablomuzda oluşturduğumuz partition ları çekerek kontrol edebiliriz.

SELECT nmsp_parent.nspname AS parent_schema,
parent.relname AS parent,
nmsp_child.nspname AS child_schema,
child.relname AS child
FROM pg_inherits
JOIN pg_class parent ON pg_inherits.inhparent = parent.oid
JOIN pg_class child ON pg_inherits.inhrelid = child.oid
JOIN pg_namespace nmsp_parent ON nmsp_parent.oid = parent.relnamespace
JOIN pg_namespace nmsp_child ON nmsp_child.oid = child.relnamespace
WHERE parent.relname=’satis’ ;

Kontrollerimizi de tamamladıktan sonra şimdi tablomuza veri basalım.

INSERT INTO satis (satis_adedi, satis_tarihi) VALUES (50 , ‘2019–04–12’);
INSERT INTO satis (satis_adedi, satis_tarihi) VALUES (80 , ‘2019–12–14’);
INSERT INTO satis (satis_adedi, satis_tarihi) VALUES (70 , ‘2019–07–15’);
INSERT INTO satis (satis_adedi, satis_tarihi) VALUES (75 , ‘2019–08–17’);

Şimdi ise bir sorgu atalım ve gerçekten o ilgili partition dan mı getiriyor sorgumuzu kontrol edelim.

select satis_adedi from satis where satis_tarihi between ‘2019–04–01’ and ‘2019–05–01’;

Şimdi EXPLAIN ederek hangi partition ları kullandığını kontrol edelim.

explain select satis_adedi from satis where satis_tarihi between ‘2019–04–01’ and ‘2019–05–01’;

Gördüğünüz üzere Where bloğunda ki tarih sorgulamalarımızın doğrultusunda satislar_2019_04 ve satislar_2019_05 partitionlarını kullandığını görmekteyiz.

Kolay Gelsin.

--

--