Bir tabloda yer alan verileri kendi belirlediğiniz kümeler halinde istediğiniz diskte tutabileceğinizi biliyor muydunuz? Bu yazımızda birçok farklı amaç için kullanabileceğiniz bu güzel özelliği, table partition yapısını anlatacağız.
Hemen aklıma gelen birkaç örnek ile ne için kullanılabileceğinden bahsedelim. Zamanla büyüyen bir tablomuz olduğunu düşünelim. Tabloyu yönetmemiz günden güne zorlaşacak, index bakım süreleri her geçen gün artacaktır. Hatta eski verilerin çok az sorgulandığı ancak yeni verilerin çok sık sorgulandığı bir durumda olabilir. Böyle bir durumda partition işleminin bize ne gibi bir faydası olabilir?
- Yeni eklen verileri hızlı disklere konumlandırabiliriz.
- İndex bakımlarını sadece belirlediğimiz aralıktaki verileri kapsayacak şekilde ayarlayabiliriz.
- Partition Switch işlemi ile TB’larca veriyi saniyeler içerisinde taşıyabilirsiniz.
Şimdi gelelim nasıl yapıldığına.
Öncelikle partitionlarımızı ekleyeceğimiz file groupları ekleyerek başlamamız gerekiyor.
Yukarıda yer alan resimde görüldüğü gibi 3 adet file group ekledim.
Ardından bu file grouplara file eklememiz gerekiyor.
File eklerken kırmızı ile işaretlediğim kısma dikkat etmeniz gerekir. Oluşturduğumuz fileları daha önce oluşturduğumuz file grouplara tanımlamalıyız.
Belirlediğimiz diskler üzerine belirlediğimiz fileları oluşturduk şimdi sıra geldi tablomuzu oluşturmaya ve içerisindeki verileri belirlediğimiz bir aralığa göre belirlediğimiz filelara yazmaya.
Bu işlemi yapmak için iki şeye ihtiyacımız var. Birisi Partition Function diğeri ise bu Partition Schema
Partition Function kısmında tabloda yer alacak verimizi hangi kritere göre bölmek istediğimizi belirtiyoruz. Partition Schemada ise bu belirlediğimiz aralığı hangi dosyalara yazacağımızı belirliyoruz. Ben tablomu otomatik artan bir bigint alanına göre bölmek istiyorum. Ve bunun için aşağıdaki script ile partition function oluşturuyorum.
1 2 3 |
CREATE PARTITION FUNCTION PF_OrderByBigIntId(Bigint) AS RANGE RIGHT FOR VALUES (100000,200000) |
— PF_OrderByBigIntId(Bigint) fonksiyonum adını ve alacağı değerin Bigint formatında olduğunu belirtiyorum.
— RIGHT – LEFT ifadesi ile alakalı bilgiyi daha geniş bir zamanımda uzunca anlatmam gerekecek.
— Values kısmında ise 100000 diyerek 0 ile 100000 arasında kalan değerleri, ardından 100000 ile 200000 arasında kalan değerleri aralık olarak belirliyorum.
Sıra geldi partition scheme oluşturmaya.
1 2 3 |
CREATE PARTITION SCHEME PS_OrderByBigIntId AS PARTITION PF_OrderByBigIntId TO (FG_partition1, FG_partition2, FG_partition3) |
— PS_OrderByBigIntId şemamızın ismini belirtiyor.
— AS PARTITION PF_OrderByBigIntId ifadesi ile parçalama fonksiyonumu tanımlıyorum.
— Dikkatinizden kaçmamıştır, oluşturduğumuz fonksiyonda 2 aralık belirtmemize rağmen burada 3 file group belirtiyoruz, bunun sebebi aralığın dışında kalacak değerler için de en az bir file istemesidir. Yani 200000 den yüksek bir değerli kayıt gelirse FG_partition3 dosyasına yazacaktır.
Sıra geldi tablomuzu oluşturmaya.
1 2 3 4 5 6 7 8 9 |
CREATE TABLE [dbo].[sahis]( [Id] [bigint] IDENTITY(1,1) NOT NULL, [Ad] [nvarchar](50) NULL, PRIMARY KEY (Id) ) ON PS_OrderByBigIntId(Id) |
— Gördüğünüz gibi tabloyu oluşturuken ON [PRIMARY] ibaresi yerine şemamızın adını yazdık ve Id kısmını da parametre olarak içerisine ekledik.
— Tabloya veri eklemek için aşağıdaki gibi basit bir script yazıp testini yapabiliriz.
1 2 3 4 5 6 7 8 9 10 11 |
DECLARE @sayi int = 200001 WHILE(@sayi>1) BEGIN INSERT INTO sahis (Ad) values ('a') SET @sayi=@sayi-1 END |
— Aşağıdaki script yardımı ile hangi partitionda kaç adet veri olduğunu da görebiliriz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
SELECT OBJECT_NAME(si.object_id) AS object_name ,pf.NAME AS pf_name ,ps.NAME AS partition_scheme_name ,p.partition_number ,ds.NAME AS partition_filegroup ,rv.value AS range_value ,( CASE pf.boundary_value_on_right WHEN 0 THEN 'RAGE_LEFT' ELSE 'RANGE_RIGHT' END ) AS range_direction ,SUM(CASE WHEN si.index_id IN (1,0) THEN p.rows ELSE 0 END) AS num_rows FROM sys.destination_data_spaces AS dds INNER JOIN sys.data_spaces AS ds ON dds.data_space_id = ds.data_space_id INNER JOIN sys.partition_schemes AS ps ON dds.partition_scheme_id = ps.data_space_id INNER JOIN sys.partition_functions AS pf ON ps.function_id = pf.function_id LEFT JOIN sys.partition_range_values AS rv ON pf.function_id = rv.function_id AND dds.destination_id = CASE pf.boundary_value_on_right WHEN 0 THEN rv.boundary_id ELSE rv.boundary_id + 1 END LEFT JOIN sys.indexes AS si ON dds.partition_scheme_id = si.data_space_id LEFT JOIN sys.partitions AS p ON si.object_id = p.object_id AND si.index_id = p.index_id AND dds.destination_id = p.partition_number LEFT JOIN sys.dm_db_partition_stats AS dbps ON p.object_id = dbps.object_id AND p.partition_id = dbps.partition_id WHERE si.object_id = OBJECT_ID('sahis') GROUP BY ds.NAME ,p.partition_number ,pf.NAME ,pf.type_desc ,pf.fanout ,pf.boundary_value_on_right ,ps.NAME ,si.object_id ,rv.value ORDER BY p.partition_number |