25 Kasım 2015 Çarşamba

Normalizason Nedir?

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çunYılmazAhmetToyotaLevent, Etiler, Ulus
MetinSeyyarMehmetHondaBakırköy, Ataköy, Yeşilköy
MetinSeyyarTolgaFordKandilli, 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:
  • Aynı tablo içinde tekrarlayan kolonlar bulunamaz,
  • Her kolonda yalnızca bir değer bulunabilir (bkz. "Semt" kolonu)
  • Her satır bir eşsiz anahtarla tanımlanmalıdır (Unique Key - Primary Key)
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çunYılmazAhmetToyotaLeventEtilerUlus
MetinSeyyarMehmetHondaBakırköyAtaköyYeşilköy
MetinSeyyarTolgaFordKandilliBeylerbeyiKuzguncuk

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çunYılmazAhmetToyotaLevent
OrçunYılmazAhmetToyotaEtiler
OrçunYılmazAhmetToyotaUlus
MetinSeyyarMehmetHondaBakırköy
MetinSeyyarMehmetHondaAtaköy
MetinSeyyarMehmetHondaYeşilköy
MetinSeyyarTolgaFordKandilli
MetinSeyyarTolgaFordBeylerbeyi
MetinSeyyarTolgaFordKuzguncuk

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
1OrçunYılmazAhmetToyotaLevent
2OrçunYılmazAhmetToyotaEtiler
3OrçunYılmazAhmetToyotaUlus
4MetinSeyyarMehmetHondaBakırköy
5MetinSeyyarMehmetHondaAtaköy
6MetinSeyyarMehmetHondaYeşilköy
7MetinSeyyarTolgaFordKandilli
8MetinSeyyarTolgaFordBeylerbeyi
9MetinSeyyarTolgaFordKuzguncuk
İş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:
  • Tablo 1NF olmalıdır,
  • Anahtar olmayan değerler ile kompozit (bileşik) anahtarlar arasında kısmi (partial) bağımlılık durumu oluşmamalıdır. Kısmi bağımlılık durumu, anahtar olmayan herhangi bir değer kompozit bir anahtarın yalnızca bir kısmına bağıl ise oluşur. (Evet farkındayım çok karmaşık görünüyor, örnekte net bir şekilde anlayacaksınız. Söz...)
  • Herhangi bir veri alt kümesi birden çok satırda tekrarlanmamalıdır. Bu tür veri alt kümeleri için yeni tablolar oluşturulmalıdır.
  • Ana tablo ile yeni tablolar arasında, dış anahtarlar (foreign key) kullanılarak ilişkiler tanımlanmalıdır.
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
1OrçunYılmaz
2MetinSeyyar

Servis Tablosu 
CidSoforAracSemt
1AhmetToyotaLevent
1AhmetToyotaEtiler
1AhmetToyotaUlus
2MehmetHondaBakırköy
2MehmetHondaAtaköy
2MehmetHondaYeşilköy
2TolgaFordKandilli
2TolgaFordBeylerbeyi
2TolgaFordKuzguncuk
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ı 2NF olmalıdır,
  • Anahtar olmayan hiç bir kolon bir diğerine (anahtar olmayan başka bir kolona) bağıl olmamalı ya da geçişken fonksiyonel bir bağımlılığı (transitional functional dependency) olmamalıdır. Başka bir deyişle her kolon eşsiz anahtara tam bağımlı olmak zorundadır.
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
1OrçunYılmaz
2MetinSeyyar

Servis Tablosu 
CidSidSemt
11Levent
11Etiler
11Ulus
22Bakırköy
22Ataköy
22Yeşilköy
23Kandilli
23Beylerbeyi
23Kuzguncuk

Şoför Tablosu
SidSoforArac
1AhmetToyota
2MehmetHonda
3TolgaFord
Ö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:
  • Veri Tabanı 3NF olmalıdır,
  • Her determinant (belirleyici kolon) aynı zamanda bir aday anahtar olmalıdır.
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
1OrçunYılmaz
2MetinSeyyar

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

Semt Tablosu 
SemtSid
Levent1
Etiler1
Ulus1
Bakırköy2
Ataköy2
Yeşilköy2
Kandilli3
Beylerbeyi3
Kuzguncuk3

Şoför Tablosu
SidSoforArac
1AhmetToyota
2MehmetHonda
3TolgaFord
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:
  • Veri Tabanı 3NF olmalıdır,
  • Çok-değerli bağımlılıkları (Multli-Valued dependency) olmamalıdır.
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...
kaynak: beltslib. net

Hiç yorum yok :

Yorum Gönder