avatar

Veri Tabanlarında Normalizasyon
Bakkal defteri ile veri tabanı arasındaki en temel fark: Normalizasyon...

17/07/2014
Hakan Özakar

İ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:

  • 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ç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:

  • 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
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ı 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
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:

  • 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
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:

  • 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...

 

Yorumlar Yorum Yap

  • Ahmet KUYUMCU

    elinize sağlık çok güzel anlatmışsınız. 4NF (4. Normal Form) için de bir makale yazarsanız güzel olur. Teşekkürler

    Ahmet KUYUMCU 22/05/2018 11:07
  • Sümeyye

    Çok İyi. Muazzam bir anlatım. Umarım vizeyi geçerim stop.

    Sümeyye 01/04/2018 00:43
  • osman

    güzel olmuş hakkaten peki normalizayonun zararları varmıdır ??

    osman 10/01/2018 15:20
  • fuat

    elinize sağlık harbiden cok iyi bir anlatım

    fuat 17/11/2017 14:22
  • Atacan

    Gayet akıcı ve yalın bir anlatım olmuş. Bu yazı sayesinde Normalizasyon konusunun teorisini iyi kavradım. Çok sağolun.

    Atacan 18/08/2017 10:42
  • Oğuzhan

    Anlayamadım çünkü anlatamamış diyen kişiler, gidin başka iş yapın. Ben bu kadar sade anlatabilen birini ilk kez gördüm. Hala anlamıyorsanız sorun şu ki kafayı yormadan veri tabanı öğrenilmez.

    Oğuzhan 04/08/2017 16:02
  • Mustafa

    Yemin ederim boyle icten bir anlatimi simdiye kadar gormedim..Elinize saglik,cok tesekkur ederim :)

    Mustafa 29/05/2017 06:19
  • zutters

    teşekkürler güzel anlatım olmuş

    zutters 12/04/2017 15:17
  • Mustafa

    Üniversitemizdeki bölüm başkanından daha iyi anlattığınız gerçeği ile sizi baş başa bırakıyorum =) Thumbs up!

    Mustafa 11/04/2017 00:03
  • melih

    HARİKA BİR ANLATIM TEŞEKKÜRLER UZUN SÜREDİR ANLAYAMADIGIM NORMALİZASYONU ANLADIM SONUNDA

    melih 07/03/2017 15:20
  • akif

    Hocam işine karışmak gibi olmasın ama 3.NF \'de yaptığın şöför tablosunun 2.NF de olması gerekmez mi herhangi bir veri alt kümesi birden çok satırda tekrarlanmamalıdır kuralına göre. Elinize sağlık.

    akif 30/01/2017 20:02
  • Mert

    Akıcı ve net bir anlatım olmuş. Teşekkürler.

    Mert 01/01/2017 16:53
  • mehmet

    ben daha bu sene başladım veritabanına sitede weri tabanı kullnamak istiyorum bana göre adam anlatammış hoca daha iyi anlatı düşünrek benim yerimde olsanız

    mehmet 22/12/2016 21:24
  • nes

    2 dönem 2 farklı hocadan veri tabanı dersi aldım; şu normalizasyon olayını bir anlayamadım. Ne güzel anlattınız. Allah razı olsun.

    nes 11/11/2016 11:33
  • adnan

    arkadaşla yazılıya çalışıyoz en iyi site burası :)

    adnan 11/11/2016 08:29
  • hadiordan

    bi de iyi anlayacaksınız söz demiş ya o kadar saçma ve terimsel anlatmışsın ki hiç bi şey anlamadım !!

    hadiordan 26/10/2016 01:51
  • Muharrem

    Normalizasyonun daha ileri seviyelerini de örneklerle anlatabilir misiniz? Bu konu içinde teşekkür ederim. Güzel bir paylaşım olmuş.

    Muharrem 29/07/2016 11:04
  • Mesut P.

    Teşekkürler çok güzel bir şekilde anlatmışsınız.

    Mesut P. 13/04/2016 18:25
  • Batuhan Göksu

    MySQL ve PostgreSQL daha doğrusu ilişkisel veritabanları kullananlar için okunması ve bilgisi dahilinde olması gereken bilgiler ancak max 3 yıla kadar ilişkisel veritabanlarının geçerliliği çok fazla olmaz çünkü MongoDB, CouchDB gibi NoSQL veritabanları hızla yayılıyor ve çok büyük firmalarda geçiş sürecine girdiler ancak bankalar bu durumun dışında kalabilirler. Şuanda NoSQL veritabanları hız gerektiren ve geleneksel ilişkisel veritabanlarının (rdbms) hantal ve yavaş kaldığı yapılarda kullanılmaktadır. NoSQL kullanılması durumunda bile normlizasyon'a önem verilmesi gerekiyor. Bu güzel bilgin için teşekkürler Hakan.

    Batuhan Göksu 05/08/2014 13:45