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.
Calisan | Soyad | Sofor | Arac | Semt |
---|---|---|---|---|
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:
- 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
Calisan | Soyad | Sofor | Arac | Semt 1 | Semt 2 | Semt 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
Calisan | Soyad | Sofor | Arac | Semt |
---|---|---|---|---|
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
Id | Calisan | Soyad | Sofor | Arac | Semt |
---|---|---|---|---|---|
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:
- 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
Id | Calisan | Soyad |
---|---|---|
1 | Orçun | Yılmaz |
2 | Metin | Seyyar |
Servis Tablosu
Cid | Sofor | Arac | Semt |
---|---|---|---|
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ı 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
Id | Calisan | Soyad |
---|---|---|
1 | Orçun | Yılmaz |
2 | Metin | Seyyar |
Servis Tablosu
Cid | Sid | Semt |
---|---|---|
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
Sid | Sofor | Arac |
---|---|---|
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:
- 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
Id | Calisan | Soyad |
---|---|---|
1 | Orçun | Yılmaz |
2 | Metin | Seyyar |
Servis Tablosu
Cid | Semt |
---|---|
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
Semt | Sid |
---|---|
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
Sid | Sofor | Arac |
---|---|---|
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.
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