Normalleştirme (Normalisation, Normalizasyon)
Yazan: Şadi Evren ŞEKER
Bu yazının amacı, site üzerinde daha önceden anlatılmış olan birinci normal form (1NF),
ikinci normal form (2NF) ve üçüncü normal form (3NF) konularını kapsayan bir örnek çözmektir.
Genel olarak çok sayıda sınav sorusunda normalleştirme için hayali bazı tablolar sunulur ve bu tabloların normalleştirilmesi (normalizasyonu) istenir.
Örnek olarak aşağıdaki tabloyu ele alalım.
Yukarıdaki tabloda görüldüğü üzere 4 adet kolon ve her kolonda çeşitli sayılar ile gösterilmiş değerler bulunmaktadır. Bu tablonun üzerinde normalleştirme yapmaya başlamadan önce bazı konuları açıklayalım.
Örneğin yukarıdaki tabloda bir aday anahtar (candidate key) bulmamız istense ne yaparız?
Bir aday anahtar bulma işlemi için en kolay yol, tablonun birincil anahtarını (primary key) bulmaktan geçer. O halde sorumuzu öncelikle tablonun birincil anahtarını (primary key) bulmak üzere değiştirelim:
Yukarıdaki tabloda, satır bazlı olarak tekrar etmeyen bir kolon var mıdır?
Cevap : D kolonudur. Dikkat edilirse D kolonu, her satırda farklı bir değer almıştır. Demek ki tek bir kolonun birincil anahtar (primary key) olmasını istersek, D kolonunu seçmemiz yerinde olur.
Peki birden fazla kolon alınması durumunda hangi kolonları seçebiliriz?
Cevap: D kolonunun zaten her satırda tekrarsız olduğunu (unique) biliyoruz. Dolayısıyla D kolonu ile birlikte hangi kolon alınırsa alınsın bu kolonlar da tekrarsız (unique) olacaktır.
Ancak acaba D kolonunu almadan bir asil anahtar ( primary key) bulunabilir mi?
Cevap: Evet vardır. Örneğin (A,B) ikilisi de tablodaki her satırda tek başına tekrarsız (unique) olma özelliğindedir. Bir önceki cevabımızdan çıkardığımız üzere, (A,B) ikilisi ile birlikte alınacak diğer bir kolon da (örneğin C ) bu durumda birincil anahtar (primary key) olma özelliğini taşıyacaktır.
Yukarıdaki cevapların doğru olmasına karşılık, birincil anahtar (primary key) seçimi yapılırken en az sayıda kolonu içeren alternatifin seçilmesi yerinde olur. Bu anlamda, yukarıdaki anahtar ihtimallerinin hepsi birer aday anahtar (candidate key) olarak değerlendirilebilir ancak birincil anahtar olarak D kolonun tek başına seçilmesi yerinde olur.
Gelelim bir diğer soruya:
Yukarıdaki tabloya, aşağıdaki şekilde ilave bir kolon eklediğimizi düşünelim:
A | B | C | D | E |
1 | 1 | 1 | 2 | X |
1 | 2 | 1 | 3 | Y |
2 | 2 | 1 | 4 | Y |
2 | 1 | 1 | 5 | X |
Yeni tablomuzda bulunan fonksiyonel bağlılıkları (functional dependency) çıkarmaya çalışalım:
Öncelikle, biliyoruz ki D kolonu birincil anahtardır (primary key) dolayısıyla zaten D kolonu bütün kolonların fonksiyonel olarak bağımlı olduğu bir kolondur ve aşağıdaki satırların tamamı doğrudur:
D -> A , D ->B , D-> C , D-> E
Ayrıca bir dipnot olarak, her kolonun kendisine fonksiyonel bağlı olduğunu söyleyebiliriz (self functional dependency), dolayısıyla D->D ifadesi de doğrudur ancak bu ifade, genelde veritabanı normalleştirmesinde bir anlam ifade etmediğinden göz ardı edilir.
Gelelim diğer fonksiyonel bağımlılıklara. Tabloda ikili üçlü ve dörtlü fonksiyonel bağlılıklar bulunabilir. Örneğin yukarıdaki sorularda (A,B) çiftinin de bir aday anahtar olduğundan bahsetmiştik. Bu durumda (A,B) -> C, (A,B) -> D , (A,B) -> E ifadeleri de doğru olacaktır. Hatta D ile birlikte herhangi bir kolonun alınması da doğrudur. Örneğin (C,D) -> A, (C,D) -> B , (C,D) -> E ifadeleri de doğrudur. Benzer şekilde D bir aday anahtar, birden fazla kolon birleşimini de fonksiyonel olarak ifade eder. Örneğin D -> (A,B,C) veya D-> (B,C,E) veya (A,B) -> (C,D,E) ifadelerinin tamamı da doğru kabul edilebilir.
Ancak acaba tek kolon seviyesinde başka fonksiyonel bağımlılık bulunabilir mi? Bu sorunun cevabı aslında bir kolon değişirken diğer bir kolonun değerlerinin bu değişimi yansıtıp yansıtmadığıdır.
Örneğin yukarıdaki tabloda, B ve E kolonları birlikte değişmektedir. Diğer bir deyişle B(1) -> E(X) ve B(2)-> E(Y) bağlantısı bulunmaktadır. Yani B tablosundaki 1 ile E tablosundaki X ve B tablosundaki 2 ile E tablosundaki Y arasında bir birliktelik söz konusudur.
Bu anlamda, B->E ve E->B ifadeleri doğrudur. Ancak konunun daha iyi anlaşılması için tabloda ufak bir oynama yapalım:
A | B | C | D | E |
1 | 1 | 1 | 2 | X |
1 | 2 | 1 | 3 | Y |
2 | 2 | 1 | 4 | Y |
2 | 3 | 1 | 5 | X |
Yukarıdaki yeni tabloda, B kolonunun son satırı 3 olarak değiştirilmiştir. Bu durumda acaba B->E ve E->B ifadelerinden bahsedilebilir mi?
Tablonun yeni halinde E’deki her değişim, B’de bir değişimle karşılandığı için B->E ibaresi doğrudur ancak ne yazık ki E->B ibaresi kullanılamaz çünkü E, B’deki değişimleri göstermek için yetersizdir.
Ayrıca yukarıdaki tabloda, C kolonu, bütün diğer kolonlara fonksiyonel olarak bağımlıdır. Bunun sebebi C kolonunun sabit olması ve dolayısıyla bütün kolonlar tarafından doğası gereği fonksiyonel bağımlılığının ifade edilmesinin mümkün olmasıdır.
Gelelim tablomuzu normalleştirmeye. Tablomuzda bulunan fonksiyonel bağımlılıkları normalleştirme aşamasında kullanacağız. Normalleştirme işleminin amacını kısaca tabloda tekrar eden veri bırakmamak (veya en aza indirmek) olduğunu söyleyebiliriz.
Yukarıdaki son halini almış tablomuzda, B->E bağımlılığının bulunması bize aşağıdaki durumu oluşturma imkanı sağlar:
Tablo K |
Tablo M |
Görüldüğü üzere, B kolonu ve E kolonu ayrı bir tabloda tutularak, E kolonunun B kolonuna fonksiyonel bağımlılığından yararlanılmıştır. Bu durumda E kolonunun orjinal tabloda yer almasına gerek yoktur. A,B,C veya D kolonları ile birlikte karşılığı olan E kolonunu bir kişinin sorgulamak istemesi halinde, iki tablo arasında bir birleştirme (join) işlemi uygulanacak ve istenen veriye kolaylıkla ulaşılabilecektir. Bu durumda K tablosundaki B kolonu bir yabancı anahtar (foreign key) olmuş ve M tablosundaki B kolonu ise birincil anahtar (primary key) olmuştur denilebilir.
Gelelim C kolonuna. Bu kolon da herhangi bir kolona fonksiyonel bağımlı kabul edilebilir demiştik. O halde aşağıdaki şekilde bölünebilir:
Tablo K |
Tablo M |
Yukarıdaki gösterim doğru olmasına karşılık, aşağıdaki gösterim de doğrudur:
Tablo K |
Tablo M |
Tablo N |
Veya diğer bir çözüm olarak aşağıdaki çözüm de doğrudur:
Tablo K |
Tablo M |
Tablo P |
Yukarıdaki bütün çözümler doğrudur. Görüldüğü üzere, normalleştirme işleminde, tekrar eden satırlar elenmiş ve mümkün olduğunca tekrarsız satırların bırakılması amaçlanmıştır.
Burada bir soru, D->A özelliğini neden kullanmadık şeklinde sorulabilir. Yani D kolonu zaten A kolonunu veya B kolonunu belirlemektedir, o halde bu özelliği de kullanarak bir bölme işlemine daha gidilebilir mi?
Cevabı hem evet hem de hayırdır. Teorik olarak bahsedildiği gibi bir bölme olabilir. Ancak bu bölmenin hiçbir faydası olmaz. Aşağıda göstermeye çalışalım:
Tablo K |
Tablo Q |
Bir önceki şekilde bulunan tablo K’yı tablo K ve tablo Q olarak bölmeye çalıştım. Görüldüğü üzere herhangi bir satır sayısında azalma olmamıştır. Bu tip birincil anahtar kullanarak bölme işlemleri mümkün olmakla birlikte genelde normalleştirme anlamında bir fayda sağlamaz. Bu şekilde böldükten sonra, iki tablo arasında (örneğimizdeki tablo K ve Q ) sayısallık açısından (cardinality) birebir (one-to-one) ilişki kurulmaktadır ki teorik olarak iki tablo arasında birebir ilişki varsa aslında bu iki tablo, bir tablonun ikiye bölünmüş halidir denilebilir. Genelde birebir ilişki, veritabanında hız amacıyla kullanlan (bazı kolonlara istatistiksel olarak çok nadir erişim yapıldığı biliniyorsa) veya veritabanı kısıtlarından dolayı kullanılan (örneğin veri tabanımızın tablo başına sadece 10 kolon tutmaya izin verdiği durumda 15 kolonlu bir tablo oluşturmak için) bir özelliktir.
hocam cok akademik olmus. hiç bişey anlamadım.
Çok doyurucu bir yazı olmuş. Kafamda bir kaç soru işareti vardı ters bağımlılıklarla alakalı. Yani fonksiyonel bağımlılığın sağlanması için attribute’ler arasında bire bir-örten bir fonksiyon olması gerekiyor mu gerekmiyor mu vs. gibi hususlar. Bu yazı ile birlikte soru işaretlerini gidermiş oldum. Teşekkürler.
CAR_SALE(Car#,Date_Sold,Sales_Person#,Commision%,Discount_amt)
Assume that a salesperson may sold multiple cars, hence {Car#,Sales_Person#} are primary key.
FD0:Car#,Sales_Person# -> (Date_Sold,Commision%,Discount_amt). Other dependencies:
FD1: Date_Sold -> Discount_amt
FD2: Sales_Preson#-> Commisionn%
Based on given primary key is this relation 1NF,2NF,3NF? Why or why not? How would you successively normalize it completely?
Bu soru nasıl çöüzülür?
2. normal form sonunda:
1.table: Car#,Sales_Person#,Date_Sold,Discount_amt
2. table: Sales_Preson#-> Commisionn%
3. normal form sonunda:
1.table: Car#,Sales_Person#, Date_Sold
2.table: Sales_Preson#, Commisionn%
3.table: Date_Sold, Discount_amt
ilk sütunlar primary key
Kaleminize sağlık çok güzel bir anlatım olmuş