SQL Server 2016 (CTP2.1) System-Versioned Tables (Temporal Tables)

Bu post’ta uzun süredir yazmayı istediğim fakat zaman bulup yazamadığım bir konu olan SQL Server 2016 ile hayatımıza girecek Temporal Tables veya diğer ismi ile System-Versioned Tables üzerinde duracağız. Bu konuya NDA kapsamında izin verildiği kadarı ile değiniyor olacağım.

CTP 2.0 veya CTP 2.1 üzerinde bu özelliğin demo’larını yapabilirsiniz. Unutmayın bu yazıyı CTP 2.1 mevcutken, RTM çıkmadan yazıyorum.

Temporal Tables (System-Versioned Tables) nedir, ne işe yarar?

Bu özellik sayesinde tablolarınızdaki verilerin zaman içerisindeki değişimlerini gözlemleyebilir, istediğiniz bir zaman dilimi ile mevcut zamandaki halleri ile karşılaştırabilirsiniz. Kısacası bu özellik, gerçekleştireceğiniz insert-update-delete işlemlerinizi tarihsel olarak kayıt altına alır.

Microsoft, geçtiğimiz günlerde SQL Server 2016 RTM olduğunda bu özelliğin ismini artık System-Versioned Table olarak kullanacağını duyurdu. Eğer belirtilenin aksi olursa bu yazıyı güncelleyeceğim.

Ne zaman ve kimler ihtiyaç duyar?

Cevabım; herkes ve her zaman! Bu özellik olmadığında bu özelliğin yarattığı yapıyı zaten yazdığımız trigger’lar, job’lar ve T-SQL’ler ile oluşturuyorduk. Çünkü bir veritabanı yöneticisi her zaman için verilerin zaman içerisindeki değişimlerini gözlemlemek ister. Bu özelliği detaylandırmak istersek bence auditing işlemlerimizde, organizasyonel haklarda (Örneğin müdür yetkisinde olan kişilerin geçmişteki verilerin değişiklik analizine erişim yetkisinin olup, altında çalışan kişilerin sadece güncel veriye erişim yetkisinin olması gibi.) ve verilerin belirli zaman dilimi içerisindeki kıyaslanmasında kullanılabilir.

Sytem-Versioned Tablo’ların oluşturulması

Bu tabloları oluşturup kullanmaya başlamadan önce limitlerine göz gezdirmekte fayda var. Çünkü normal tablolardan farklı olarak bazı limitler mevcuttur.

 

  • History tablolar her zaman için system-versioned olarak belirlenen tablonun bulunduğu veritabanı üzerinde oluşturulur.
  • System versioning yapılan tablolar kesinlikle truncate edilemez.
  • History sorgulamalar linked-server üzerinden gerçekleştirilemez. Kesinlikle aynı instance üzerinden yapılmalıdır.
  • System versioning yapılan tablolarda kesinlikle Primary Key olmalıdır (Transactional replication mantığı gibi düşünebilirsiniz). Fakat History tablolarda Primary Key, Foreign Key veya Column Constraint kullanılmaz.
  • In-Memory OLTP altyapısındaki Memory-Optimized Tables, system versioning yapılamaz.
  • History tablolar üzerinde direkt mofidikasyon yapılamaz.
  • Change Data Capture ve Change Data Tracking sadece system versioning tablolarda kullanılabilir. History tablolarda kullanılmaz.
  • System-Versioned yapı, AlwaysOn Availability Group mimarisinde de kullanılabilir.
  • History tablolarda trigger kullanımı mümkün değildir.
  • History tablolarda index kullanımı mümkündür. Columstore index’leride bu tablolarda kullanabilirsiniz.

Öncelikle bu tablolarda kesinlikle 2 adet DATETIME2 kolon tipinde ve NOT NULL olan kolona ihtiyaç duyulmaktadır. NULL olarak oluşturmayı denerseniz aşağıdaki hata ile karşılaşacaksınızdır.

Örnekleri AdventureWorks2014 veritabanı altında gerçekleştireceğim. İlk olarak System-Versioned olarak yeni bir tablo yaratıyorum.

Oluşturduğumuz tablo Object Explorer’da aşağıdaki şekilde gözükmektedir.

Yukarıdaki örnekte SQL Server, history tablosunu kendi oluşturdu. Bunu manuel olarak biz de oluşturabiliriz. Bence herzaman için bunu tercih etmekte fayda var çünkü otomatik oluşturulan history tablolarının isimleri çok anlamlı olmuyor. History tablolar, MSSQL_TemporalHistoryFor_ diye başlarlar. Sonundaki ID ise System-Versioned olan eşleniğinin object_ id’sidir. İsterseniz bu şekilde de oluşturabilirsiniz. Fakat her seferinde SELECT OBJECT_NAME(711673583) diyip root tabloya erişme ihtiyacı duyabilirsiniz. Bu yüzden aynı örneği bu sefer history tablosunuda kendim oluşturarak tekrarlıyorum. Önceki tabloyu drop ederek başlıyoruz.

System-Versioned olan bir tabloyu yukarıdaki gibi drop etmek isterseniz aşağıdaki hata mesajı ile karşılaşırsınız. Bu duruma yukarıdaki limitasyon maddelerinde değinmiştik.

Bu yüzden öncelikle System-Versioned olan tablonun SYSTEM_VERSIONING özelliğinin OFF’a getirilip, önce parent (System-Versioned) tabloyu sonra da child (History) tabloyu drop etmelisiniz.

Öncelikle History tablosunu yaratıyorum. Ardından System-Versioned olan tabloyu yaratacağım ve birbirine bağlayacağım.

Object Explorer’da System-Versioned olan tabloya baktığımızda history tablonun belirlediğimiz isimde oluşturulduğunu görüyoruz.

System-Versioned yapılan bir tabloya sağ tıklayıp Design diyemezsiniz! System-Versioned tabloların Right-Click menüsünde Design yer almaz.

Bu sefer aynı yapıyı mevcut bir tabloda uygulayalım. Bunun için AdventureWorks2014 veritabanı altındaki Person schema’sı içerisinde yer alan 909 satır veriye sahip olan BusinessEntityContact tablosunu kullanacağım. İlk olarak tablonun kolon yapısına aşağıdaki kod ile bakıyoruz.

Kolon yapısını öğrendikten sonra bu tablonun history halinin create script’ini hazırlıyorum. Bunu yaparken yukarıda bahsettiğim o iki kolonu da ekliyorum.

History tablosunu oluşturduk fakat parent’ı ile bunu ilişkilendirmemiz gerekiyor. Bunun için BusinessEntityContact tablosunu alter ederek history tablosuna eklediğimiz SysStartTime ve SysEndTime kolonlarını ekliyoruz.

Fakat bu kolonları eklemek ile tablo System-Versioned hale gelmiyor. Bütün bu işlemleri gerçekleştirdikten sonra parent tablo üzerinde SYSTEM_VERSIONING ‘i aşağıdaki gibi açıp, history tablo’sunun hangisi olduğunu göstermemiz gerekiyor.

Object Explorer’a tekrardan bakıyoruz ve Person schema’sı altındaki BusinessEntityContact tablosunun System-Versioned hale geldiğini görüyoruz.

System-Versioned Tablo ile History Tablonun Sorgulanması ve Kullanımı

T-SQL ile System-Versioned yapıyı parent/child ilişkisinde listelemeniz mümkündür. Bunun için sys.tables altındaki history_table_id kolonunu recursive olarak dönüp object_id ile birleştirmeniz yeterli olacaktır.

System-Versioned tabloların yukarıda bahsettiğimiz period kolonlarını listelemek için sys.periods altındaki start_column_id ve end_column_id ile sys.columns altındaki object_id’leri birleştirerek aşağıdaki şekilde kullanabilirsiniz.

Bu bölümde yapacağımız demo’da yukarıda yaptığımız son örnek üzerinden devam edeceğiz. Yukarıdaki örnekte mevcut bir tabloyu System-Versioned hale getirdik. Şuan için History tablosu boş durumda. Aşağıdaki gibi kontrol ediyoruz.

History tablosunu test edebilmek için BusinessEntityContact tablosunda bir update uyguluyorum.

54 satırlık bir veriyi değiştirmiş olduk. Tekrardan History tabloyu sorguluyorum.

Gördüğünüz gibi update ettiğimiz o 54 satırlık veri History tablosuna gelmiş durumda. Şimdi ise Sytem-Versioned tablo (parent) üzerinden ContactTypeID’si 17 olanları sorguluyorum.

Sorgu sonucunda herhangi bir veri karşımıza çıkmıyor çünkü yukarıda ContactTypeID’si 17 olanları 19 olarak update etmiştik. Verinin önceki halini görüntülemek için veriyi update ettiğiniz zamanı SYSTEM_TIME fonksiyonunda kullanıp, sorgunuzu çekmelisiniz.

Böylelikle yukarıda update ettiğimiz 54 satırlık ve eski ContactTypeID’si 17 olan verileri rahatıkla listeleyebildik. Eğer örneği kendiniz yaparken History tabloda kayıtların hangi tarih ile oluşturulduğunu hatırlamıyorsanız aşağıdaki gibi alabilirsiniz.

System-Versioned Tablo ile History Tablo Üzerinde Index ve İstatistik İşlemleri

Bu konuda herhangi bir kısıtlama bulunmamaktadır. Hem System-Versioned tabloda hem de History tablo’da index, istatistik create edip, index’leri reorganize/rebuild edebilirsiniz.

History Tablo’larda Silme İşlemleri

History tablolar üzerinde direkt silme işlemi yapamazsınız. Aşağıdaki gibi denediğinizde bunun mümkün olmadığının bilgisi karşınıza çıkacaktır.

Bunun için ilk olarak System-Versioned tablo üzerinden bu yapıyı yani SYSTEM_VERSIONING özelliğini kapamamız gerekmektedir.

Bu özelliği kapadıktan sonra silme işlemini tekrar çalıştırıyoruz ve silme işleminin başarılı olduğunu görüyoruz.

Silme işlemini gerçekleştirdikten sonra parent tablo üzerinde SYSTEM_VERSIONING ‘i yeniden başlatıyoruz.


Posted In:
0 Comments
Post Details

Leave a Reply

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload the CAPTCHA.