İçeriğe geç
academia.sh

Ders 02 / 14

İlişkisel Model

Bağıntı, satır, sütun ve alan kavramlarının tanımı; satır sırasının ve satır yinelemesinin modeldeki yeri ile SQL tablosunun bağıntıdan ayrıldığı noktalar.

İçindekiler

Önceki ders, bir metin dosyasındaki satırlar ile veritabanındaki satırlar arasında biçimlendirmeden daha derin bir fark olduğunu söyleyerek bitti. Bu dersin sorusu o farkı adlandırır: bir tablonun altında hangi matematiksel yapı durur, ve bu yapı tabloya bakarken gördüğümüz hangi ayrıntıların veriye ait olmadığını söyler?

Yanıt tek bir kavramda toplanır. İlişkisel modelde veri, tablo gibi görünen ama tablo olmayan bir nesnede tutulur: bağıntı (relation). Bu dersteki her kural, bağıntının küme kuramından gelen tanımının doğrudan sonucudur.

Alan

Bir sütunun alabileceği değerlerin kümesine o sütunun alanı (domain) denir. Şubenin bulunduğu il bir metin alanından, kitabın yayın yılı bir tam sayı alanından, kitabın ödünç verilebilirliği iki elemanlı bir doğruluk alanından değer alır.

Alan, tipten daha dardır. Yayın yılının tipi tam sayıdır; alanı ise “1450 ile 2100 arasındaki tam sayılar” olabilir. Tip, değerin nasıl saklandığını; alan, hangi değerlerin anlamlı olduğunu söyler. Şemada alan, bir kısıt (constraint) olarak yazılır:

sqlite3 :memory: <<'SQL'
CREATE TABLE kitap (
  isbn       TEXT NOT NULL,
  baslik     TEXT NOT NULL,
  yayin_yili INTEGER NOT NULL CHECK (yayin_yili BETWEEN 1450 AND 2100)
);
INSERT INTO kitap VALUES ('978-975-0000-01-1', 'Kayıp Zaman', 2019);
INSERT INTO kitap VALUES ('978-975-0000-02-8', 'Deniz Fenerleri', 20199);
SQL
Runtime error near line 7: CHECK constraint failed: yayin_yili BETWEEN 1450 AND 2100 (19)

Parmağın kaydığı bir eklemede yıl 20199 olarak yazılmıştır ve motor onu geri çevirir. Alanı şemada tanımlamamak, bu denetimi veriye yazan her programın ayrı ayrı yapmasını beklemek demektir.

Bağıntı

nn tane alan D1,D2,,DnD_1, D_2, \dots, D_n verildiğinde, bunların kartezyen çarpımı her bileşeni ilgili alandan seçilmiş bütün nn’li sıralı listelerin kümesidir. Bir bağıntı, bu çarpımın bir alt kümesidir:

RD1×D2××DnR \subseteq D_1 \times D_2 \times \dots \times D_n

Kartezyen çarpım, “yazılabilecek her şey”i verir; bağıntı, bunlardan “gerçekten doğru olanlar”ı seçer. Şube bağıntısında ('MRK', 'Merkez', 'Ankara') üçlüsü bulunuyorsa, bu kütüphanede MRK kodlu, Merkez adlı, Ankara’daki bir şubenin var olduğu bildirilmiştir. Bağıntıda bulunmayan üçlüler ise yanlış sayılır. Bir tablo, bir olgu listesidir.

Bağıntının iki parçası vardır. Başlık (heading), öznitelik adı ile alan eşleşmelerinin kümesidir ve zamanla değişmez. Gövde (body), başlığa uyan satırların kümesidir ve her eklemede, silmede, güncellemede değişir. Başlıktaki öznitelik sayısına bağıntının derecesi (degree), gövdedeki satır sayısına kardinalitesi (cardinality) denir.

Satır ve Sütun

Gövdedeki her eleman bir satır, kuramsal adıyla bir demettir (tuple). Satır, öznitelik adlarından değerlere giden bir eşlemedir: sube_kodu özniteliğine 'MRK', ad özniteliğine 'Merkez' karşılık gelir.

Başlıktaki her öğe bir sütundur ve bir özniteliğe (attribute) karşılık gelir. Sütun bir ada ve bir alana sahiptir; sıra numarasına değil. sube bağıntısında ikinci sütun diye bir kavram yoktur, ad sütunu vardır.

Buradan iki sonuç doğar ve ikisi de kullanımda sık unutulur.

Satırların Sırası Veriye Ait Değildir

Gövde bir kümedir; kümenin elemanları sıralı değildir. Bir sorgu satırları hangi sırayla verirse versin, o sıra veriden değil, motorun seçtiği erişim yolundan gelir. Aynı tabloya bir dizin eklemek, hiçbir satırı değiştirmeden sonucun sırasını değiştirmeye yeter:

sqlite3 :memory: <<'SQL'
.headers on
.mode box
CREATE TABLE sube (sube_kodu TEXT, ad TEXT, il TEXT);
INSERT INTO sube VALUES ('MRK', 'Merkez', 'Ankara'),
                        ('BHC', 'Bahçelievler', 'Ankara'),
                        ('KDK', 'Kadıköy', 'İstanbul');
SELECT sube_kodu, ad FROM sube;
CREATE INDEX sube_ad ON sube (ad, sube_kodu);
SELECT sube_kodu, ad FROM sube;
SQL
┌───────────┬──────────────┐
│ sube_kodu │      ad      │
├───────────┼──────────────┤
│ MRK       │ Merkez       │
│ BHC       │ Bahçelievler │
│ KDK       │ Kadıköy      │
└───────────┴──────────────┘
┌───────────┬──────────────┐
│ sube_kodu │      ad      │
├───────────┼──────────────┤
│ BHC       │ Bahçelievler │
│ KDK       │ Kadıköy      │
│ MRK       │ Merkez       │
└───────────┴──────────────┘

İki sorgu aynıdır, veri aynıdır, sıra farklıdır. İkinci sorgu artık tabloyu değil, ada göre düzenli tutulan dizini okumaktadır. Hangi erişim yolunun seçileceği motora göre değişir; kural olarak sıralı sonuç isteniyorsa sıralama açıkça istenmelidir. Sırayı açıkça istemeyen bir program, doğruluğunu tesadüfe bağlamıştır.

Yinelenen Satırlar ve Çok Küme

Küme kuramında bir eleman ya kümededir ya değildir; iki kez bulunamaz. Bağıntı tanımı gereği yinelenen satır barındırmaz. SQL tablosu ise bu noktada bağıntıdan ayrılır: anahtar tanımlanmamışsa aynı satır iki kez yazılabilir.

sqlite3 :memory: <<'SQL'
.headers on
.mode box
CREATE TABLE sube (sube_kodu TEXT, ad TEXT, il TEXT);
INSERT INTO sube VALUES ('MRK', 'Merkez', 'Ankara');
INSERT INTO sube VALUES ('MRK', 'Merkez', 'Ankara');
SELECT COUNT(*) AS satir, COUNT(DISTINCT sube_kodu) AS farkli_kod FROM sube;
SQL
┌───────┬────────────┐
│ satir │ farkli_kod │
├───────┼────────────┤
│ 2     │ 1          │
└───────┴────────────┘

SQL tablosu bir küme değil, bir çok kümedir (multiset): aynı değer birden çok kez bulunabilir. Bu, modelin bir eksiği değil, kuramdan bilinçli bir sapmadır — yinelenenleri elemek sıralama ya da karma gerektirir, yani ücretlidir. Sonuç şudur: tablonun bağıntı gibi davranması kendiliğinden olmaz, şemada istenir. Bunu isteme yolu anahtar tanımlamaktır ve sıradaki dersin konusu budur.

Bağıntı Değişkeni ve Şema

Yukarıdaki sube tablosu, zaman içinde değişen bir değeri tutar: bugün üç satır, yarın dört. Kuramda bu ayrım adlandırılmıştır. Bağıntı değişkeni (relation variable) bir addır ve o adın herhangi bir andaki değeri bir bağıntıdır. CREATE TABLE bir bağıntı değişkeni oluşturur; INSERT onun değerini değiştirir.

Buradan, veritabanı çalışmasının iki ayrı düzlemi çıkar. Şema (schema), bağıntı değişkenlerinin başlıklarını ve üzerlerindeki kısıtları belirtir; nadiren değişir ve değiştiğinde göç gerektirir. Örnek (instance), belirli bir andaki değerler bütünüdür; sürekli değişir. Bir tasarım hatası şemadadır, bir veri hatası örnektedir; ilkini düzeltmek ikincisinden pahalıdır.

Değerin Bölünmezliği

Modelin son kuralı, satır ile sütunun kesiştiği yerde tek bir değer bulunmasıdır. Şubenin telefon numaraları için '0312-000-0001, 0312-000-0002' biçiminde tek bir metin yazmak, oraya bir liste sıkıştırmak demektir. Sistem o metni bölünmez sayar: içindeki ikinci numarayı arayan bir sorgu yazılamaz, bir numaranın kaldırılması metin düzenlemeye dönüşür, numara üzerinde kısıt tanımlanamaz.

Bunun karşılığı, çok değerli olguyu ayrı bir bağıntıya taşımaktır — her telefon numarası kendi satırında, şube koduyla birlikte. Bu kural Normalizasyon konusunda birinci normal form adıyla biçimselleştirilecek; şimdilik modelin bir gereği olarak durur.

Özet

  • Bağıntı, öznitelik alanlarının kartezyen çarpımının bir alt kümesidir; başlığı sabit, gövdesi değişkendir.
  • Alan, bir sütunun anlamlı değerler kümesidir ve tipten dardır; şemada kısıt olarak yazılır.
  • Gövde bir küme olduğundan satır sırası veriye ait değildir; sıralı sonuç isteniyorsa açıkça istenmelidir.
  • SQL tablosu çok küme olduğu için yinelenen satır kabul eder; bağıntı gibi davranması şemada anahtar tanımlanmasına bağlıdır.
  • Şema bağıntı değişkenlerini ve kısıtlarını, örnek ise belirli bir andaki değerleri belirtir.

Sonraki Adım

Bu ders iki kez aynı yere çıktı: satırların birbirinden ayırt edilebilmesi gerekiyor, ve bu ayırt etme şemada söylenmedikçe gerçekleşmiyor. Sıradaki ders, bir satırı tek başına belirleyen sütun kümesini tanımlar; birden çok adayın bulunduğu durumda hangisinin seçileceğini tartışır ve bir bağıntının satırlarını başka bir bağıntının satırlarına bağlayan anahtarı kurar.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat