VERI TABANLARINDA NORMALIZASYON

İster web uygulaması ister masaüstü yazılım olsun hemen her bilgisayar programının en temel ihtiyacı veri tabanıdır kuşkusuz. Ancak ne acıdır ki yazılımcıların, özellikle de web geliştiricilerinin en donanımsız olduğu alanlardan biri de budur sanırım.

Eğer siz de projeniz için bir veri tabanı oluştururken, ihtiyaç duyduğunuz tüm bilgileri tek bir tabloya, tesbih tanesi gibi dizenlerdenseniz bu konu sizi çok ilgilendiriyor çünkü bakkal defteri ile veri tabanı arasındaki en temel fark normalizasyondur.

 

Güçlü, hızlı ve sağlıklı bir veri tabanı oluşturmanın olmazsa olmazı normalizasyon yapmaktır.

Geçenlerde orta çaplı bir proje için yaklaşık 125.000 satır veri tutması gereken bir veri tabanı tasarlamam gerekti. Tasarımı tamamlayıp kayıtları veri tabanına aktardıktan sonra veri tabanının performansını görebilmek için üzerinde bazıları basit, bazıları karmaşık sorgular çalıştırdım. Gördüm ki bazı karmaşık sorgularda cevap süresi 6 - 7 saniyeyi bulabiliyor.

Bu makaleyi yazmaya karar verince aynı veri tabanını bakkal defteri formunda, yukarıda bahsettiğim gibi tesbih tanesi normunda tekrar oluşturup aynı cevap kümesini alan sorgular çalıştırdım.

İlk veri tabanında cevap süresi 6sn. olan sorgunun eşdeğeri bu veri tabanında 1 dakikadan uzun sürdü... 10 katından fazla.

Peki bu kadar büyük farkı doğuran neydi?

 

Normalizasyon Nedir?

Normalizasyonun iki temel amacı vardır. Veri tabanında veri tekrarlarını ortadan kaldırmak ve veri tutarlılığını (doğruluğunu) artırmak.

Normalizasyon, veri tabanlarına seviyelerle (normal formlar) uygulanır. Bir veri tabanının bu normal formlardan herhangi birine uygun olduğunu söyleyebilmek için, söz konusu normal formun tüm kriterlerini eksiksiz yerine getiriyor olması şarttır.

Başarılı bir şekilde uygulandığında normalizasyon işlemi veri tabanının süratini büyük oranda artırır. Veri tabanının sabit diskteki boyutunu azaltır. Ayrıca veri tutarlılığını artırarak veri tekrarlarını engeller. Bilmem, özellikle güncelleme ve silme işlemlerinde ortaya çıkabilecek aksaklıkları minimize ettiğini söylemeye gerek var mı?

 

Normal Formlar

Basitçe tanımlamak gerekirse, normal formlar normalizasyon seviyeleridir. Bu seviyeler gereksiz veri tekrarlarını ne derecede engellediği ve tutarlılığı ne kadar sağladığına bağlı olarak derecelendirilir. Seviye yükseldikçe veri tutarlılığı artar, veri tekrarı düşer.

Normalizasyon seviyeleri 1NF (Birinci Normal Form), 2NF, 3NF, BCNF(Boyce-Codd Normal Form, 3.5NF'de denir), 4NF şeklinde adlandırılır ve yukarı doğru devam eder. Ancak daha yukarı normalizasyon seviyeleri çok nadiren kullanılır çünkü çoğu zaman uygulanması mümkün olmayabilir.

Konuyu detaylandırabilmek için bir veri tabanı oluşturalım ve normalizasyonunu yapalım. Tabloda bir teknik destek firmasının çalışanları, servis araçları, servis soförleri ve servis verilen semtler bulunsun. Her bir şoför tek araç ile semt bazında servis yapmaktadır. Örneğin şoför "Ahmet", teknik elemanları (çalışanları) "Toyota" araçla, "Levent", "Etiler" ve "Ulus" semtlerindeki destek çağrılarına götürmektedir.

CalisanSoyadSoforAracSemt
Orçun Yılmaz Ahmet Toyota Levent, Etiler, Ulus
Metin Seyyar Mehmet Honda Bakırköy, Ataköy, Yeşilköy
Metin Seyyar Tolga Ford Kandilli, Beylerbeyi, Kuzguncuk

 

Çoğu programcı için veri tabanı tasarımı burada biter. Cılkını çıkartmaya gerek yok, değil mi? Bu arkadaşlara tavsiyem: Wordpress'ten şaşmayın, sizi o paklar...

İşin doğrusu, veri tabanımızı oluşturmaya henüz başladık.

 

1NF (1. Normal Form)

Bir veri tabanının 1NF olabilmesi için aşağıdaki özellikleri karşılayabilmesi gerekir:

Veri tabanımızda ikinci kurala açıkça uymayan bir kolon var: Semt. Bu durumu düzeltmek için tekrar düzenleyelim:

Ana Tablo

CalisanSoyadSoforAracSemt 1Semt 2Semt 3
Orçun Yılmaz Ahmet Toyota Levent Etiler Ulus
Metin Seyyar Mehmet Honda Bakırköy Ataköy Yeşilköy
Metin Seyyar Tolga Ford Kandilli Beylerbeyi Kuzguncuk

 

Bir sorun var. Tablo bu şekliyle birinci kuralla çelişti. Semt 1, Semt 2, Semt 3 tekrarlayan kolonlar. Bir daha deneyelim:

Ana Tablo

CalisanSoyadSoforAracSemt
Orçun Yılmaz Ahmet Toyota Levent
Orçun Yılmaz Ahmet Toyota Etiler
Orçun Yılmaz Ahmet Toyota Ulus
Metin Seyyar Mehmet Honda Bakırköy
Metin Seyyar Mehmet Honda Ataköy
Metin Seyyar Mehmet Honda Yeşilköy
Metin Seyyar Tolga Ford Kandilli
Metin Seyyar Tolga Ford Beylerbeyi
Metin Seyyar Tolga Ford Kuzguncuk

 

Evet, şimdi oldu. Tekrar eden kolonlar yok. Bir kolonda birden çok veri yok. Süper. Pardon? Eşsiz anahtar mı dediniz? Doğru... E, nasıl yaparız?

Önce  "aday anahtar" (candidate key) ve "eşsiz anahtar" (primary key) kavramlarına bir göz atalım o zaman:

Aday Anahtar (Candidate Key): Bir ya da daha fazla kolondan meydana gelir. Tablonun her bir veri satırını eşsiz olarak tanımlar, başka bir deyişle tabloda kaç satır olursa olsun bu kombinasyonu bulunduran birden fazla satır asla olamaz. Örneğin, "Çalışan - Soyad" kombinasyonu bir aday anahtar değildir çünkü 1, 2 ve 3üncü satırlar ve 4, 5, 6, 7, 8 ve 9uncu satırlarda değerler tekrar etmektedir. Öte yandan "Çalışan - Semt" kombinasyonu hiç bir şekilde tekrar etmiyor. Öyleyse "Çalışan - Semt" kombinasyonu bir aday anahtardır.

Eşsiz Anahtar (Primary Key): Tablodaki aday anahtarlardan herhangi birini eşsiz anahtar olarak atayabiliriz. Bu anahtar tablodaki satırları tanımlamak için kullanılır ve bir tabloda yalnızca 1 tane eşsiz anahtar bulunabilir.

Tablomuza dönecek olursak, "Çalışan - Semt" kombinasyonunu eşsiz anahtar olarak atayabiliriz. Elimizdeki örnek son derece basit bir tablo olduğundan sorun yok ama daha karmaşık işlerde eşsiz anahtar için kolon kombinasyonlarını pek tercih etmiyoruz. Eh, sonuçta veri tabanlarına Auto Increment (Otomatik Sayı - Otomatik Artış) fonksiyonlarını spor olsun diye koymuyorlar, değil mi?

 

Ana Tablo 

IdCalisanSoyadSoforAracSemt
1 Orçun Yılmaz Ahmet Toyota Levent
2 Orçun Yılmaz Ahmet Toyota Etiler
3 Orçun Yılmaz Ahmet Toyota Ulus
4 Metin Seyyar Mehmet Honda Bakırköy
5 Metin Seyyar Mehmet Honda Ataköy
6 Metin Seyyar Mehmet Honda Yeşilköy
7 Metin Seyyar Tolga Ford Kandilli
8 Metin Seyyar Tolga Ford Beylerbeyi
9 Metin Seyyar Tolga Ford Kuzguncuk

İşte şimdi oldu. "Id" sütununu eşsiz anahtar olarak atadık. 1NF kurallarına harfiyen uyduk. Süperiz...

 

2NF (2. Normal Form)

Bir veri tabanının 2NF olabilmesi için aşağıdaki özellikleri karşılayabilmesi gerekir:

Aslında üç ve dördüncü maddeler ikinci maddenin sonuçlarıdır. Eğer anahtar olmayan bir kolonla herhangi bir komposit anahtar arasında kısmi bağımlılık varsa her zaman tekrarlayan veri alt kümeleri oluşur. Bu durumu düzeltmek için bahis konusu alt kümeleri farklı bir tablo haline getirmeli ve elde ettiğimiz tablolar ile ana tablomuz arasındaki ilişkiyi tanımlamalıyız.

Tablomuzu bir gözden geçirelim: "Çalışan - Soyad" kombinasyonuna bakın. Çok tekrarlanıyor çünkü eşsiz anahtara verimli bir şekilde bağlayamamışız. Bunu düzeltmek için tablomuzu aşağıdaki gibi ikiye bölelim ve aralarında bir ilişki oluşturalım:

Ana Tablo

IdCalisanSoyad
1 Orçun Yılmaz
2 Metin Seyyar

 

Servis Tablosu 

CidSoforAracSemt
1 Ahmet Toyota Levent
1 Ahmet Toyota Etiler
1 Ahmet Toyota Ulus
2 Mehmet Honda Bakırköy
2 Mehmet Honda Ataköy
2 Mehmet Honda Yeşilköy
2 Tolga Ford Kandilli
2 Tolga Ford Beylerbeyi
2 Tolga Ford Kuzguncuk

Yeni tablomuz ile ana tablomuzu ilişkilendirmek için "Cid" (Çalışan ID) isimli bir kolon yarattık. Dikkat ederseniz bu kolonun aldığı değer ana tablomuzdaki eşsiz anahtarı işaret ediyor. Bu ilişkilendirmeye Foreign Key diyoruz.

Ayrıca bilmem söylemeye gerek var mı, Şoför - Araç - Semt kombinasyonu bu yeni tablomuzun eşsiz anahtarı olarak gayet iyi iş görüyor.

Evet, artık bu noktada 2NF işini hallettik diyebiliriz.

 

3NF (3. Normal Form)

Bir veri tabanının 3NF olabilmesi için aşağıdaki özellikleri karşılayabilmesi gerekir:

Veri tabanımızı 3NF şartlarına uydurabilmek için anahtar olmayan ve eşsiz anahtara tam bağımlı olmayan tüm kolonları kaldırmalıyız. Dikkat ederseniz bizim tablomuzda "Araç" kolonu eşsiz anahtarımıza değil "Şoför" kolonuna bağımlı. Birbirine bağlı olan bu iki kolonu (Şoför - Araç) ayrı bir tabloya ayırmamız ve tablomuzla aralarında bir ilişki yaratmamız gerekiyor.

Ana Tablo

IdCalisanSoyad
1 Orçun Yılmaz
2 Metin Seyyar

 

Servis Tablosu 

CidSidSemt
1 1 Levent
1 1 Etiler
1 1 Ulus
2 2 Bakırköy
2 2 Ataköy
2 2 Yeşilköy
2 3 Kandilli
2 3 Beylerbeyi
2 3 Kuzguncuk

 

Şoför Tablosu

SidSoforArac
1 Ahmet Toyota
2 Mehmet Honda
3 Tolga Ford

Öncelikle şoför tablosu adında yeni bir tablo oluşturduk. Bu tabloda Sid (Şoför ID) adıyla bir eşsiz anahtar yarattık ve Servis tablomuzdaki Sid kolonundan bu eşsiz anahtara referans vererek foreign key oluşturduk.

3NF'i de gördük ya... Artık karada ölüm yok.

 

BCNF / 3.5NF (Boyce-Codd Normal Form)

Bir veri tabanının 3.5NF olabilmesi için aşağıdaki özellikleri karşılayabilmesi gerekir:

Determinant: Aynı satırdaki diğer kolon değerlerini belirlemek için kullanılan kolon kümesi determinant olarak adlandırılır.

Servis tablomuza dikkatle baktığımızda iki tane determinant olduğunu görebiliriz. Semt kolonu, Cid - Sid kombinasyonunun; Sid ise Cid kolonunun determinantıdır.

Bu noktada Semt kolonunun hali hazırda bir aday anahtar olduğunu görebiliyoruz çünkü her bir değer tekrar oluşturmaksızın tüm kayıt satırını tanımlayabilmekte. Öte yandan Sid için aynı şeyi söylemek mümkün değil çünkü tekrarlanıyor.

Elbette bu durumu düzeltmek için tabloyu ikiye ayıracak semt tablosunun değerini tabloları ilişkilendirmek için foreign key olarak kullanacağız.

Ana Tablo

IdCalisanSoyad
1 Orçun Yılmaz
2 Metin Seyyar

 

Servis Tablosu 

CidSemt
1 Levent
1 Etiler
1 Ulus
2 Bakırköy
2 Ataköy
2 Yeşilköy
2 Kandilli
2 Beylerbeyi
2 Kuzguncuk

 

Semt Tablosu 

SemtSid
Levent 1
Etiler 1
Ulus 1
Bakırköy 2
Ataköy 2
Yeşilköy 2
Kandilli 3
Beylerbeyi 3
Kuzguncuk 3

 

Şoför Tablosu

SidSoforArac
1 Ahmet Toyota
2 Mehmet Honda
3 Tolga Ford

Görülebileceği gibi artık tablolarımızın hiçbirinde aday anahtar olmayan determinant yok. Bu nedenle veri tabanımız BCNF'tir diyebiliriz.

Not: Hazır Boyce - Codd demişken: Raymond F. BoyceEdgar F. Codd.

 

4NF (4. Normal Form)

Bir veri tabanının 4NF olabilmesi için aşağıdaki özellikleri karşılayabilmesi gerekir:

Multi-Valued Dependency: Bu durum bir ya da daha çok veri satırının var olması, aynı tabloda başka bir (ya da daha çok) veri satırının bulunmasını gerektirdiğinde ortaya çıkar. Örneğin, bir yazılım firması düşünelim. Geliştirdikleri yazılımların masaüstü bilgisayarlar için olanlarını tek-kullanıcılı ve çok-kullanıcılı olarak iki versiyonla piyasaya sunuyor olsunlar. Diyelim ki bu firmanın geliştirdiği tüm yazılımları barındıran bir veri tabanı oluşturuyoruz. Bu veri tabanında bir masaüstü yazılımın tek-kullanıcılı versiyonunu eklediysek mutlaka bir başka satırda aynı yazılımın çok-kullanıcılı versiyonu için de bir kayıt açılmış olmak durumundadır...

Hali hazır örneğimizde böyle bir durum oluşmadığından 4NF uyarlaması yapılmasına gerek (ve imkan) yoktur.

 

Sonuç

En azından ilk üç seviye normalizasyonu her zaman ve mutlaka yapmak gerektiğine inanıyorum. Ancak bazı özel durumlarda (Örneğin nadiren kayıt girişi yapılan fakat sürekli yeni yeni sorgular yazılan bir veri tabanı düşünün) sorgularınızı kodlamanın biraz daha kolaylaşması için bazı kolonların birden çok tabloda tekrarlanmasını isteyebilirsiniz. Bu türden durumlarda normalizasyonu bir seviyeden sonra yapmamayı tercih edebilirsiniz. O seviyenin 3NF'den aşağı olmamasını şiddetle tavsiye ederim. Yine de hiç üşengeçlik etmesek daha iyi tabii...

 

Ne, size veri tabanı oluşturmak kolay mı demişlerdi? Veri tabanıyla Exceli karıştırmış onlar...

 

Kategori : Veritabanı