Ders 07 / 25
Sistem Kataloğu
Şema tanımının sorgulanabilir tablolarda tutulması, envanterin ve yönetim kurallarının sorguya çevrilmesi, iki kopya arasındaki şema sapmasının ölçülmesi ve kataloğun neden okunup yazılmadığı.
İçindekiler
Bu kursta şimdiye kadar sorulan her soru bir sayıyla yanıtlandı: sayfa sayısı, doluluk, çerçeve sayısı, isabet oranı. Bu sayıların kaynağı motorun kendi tuttuğu kayıtlardır ve o kayıtlar özel bir arayüzün arkasında değildir. Motor, şema hakkındaki bilgiyi sıradan tablolarda tutar ve sıradan sorgularla verir. Bu tabloların bütününe sistem kataloğu (system catalog) denir.
Kataloğun sorgulanabilir olması, yönetim işini bir belge işi olmaktan çıkarır. Hangi tabloların hangi sütunları taşıdığı, hangi dizinlerin var olduğu, hangi kısıtların tanımlandığı elle tutulan bir listede değil, veritabanının kendisinde yazılıdır — ve o liste her zaman günceldir, çünkü değişikliği yapan deyimin kendisi onu günceller.
Katalog Sıradan Bir Tablodur
Aşağıdaki blok kütüphane şemasını kurar. Şema önceki kurslardan tanıdıktır; buraya dizinler, bir görünüm ve bir değer denetimi eklenmiştir.
rm -f kutuphane.db sqlite3 kutuphane.db <<'SQL' CREATE TABLE sube ( sube_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, sehir TEXT NOT NULL ); CREATE TABLE uye ( uye_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, eposta TEXT UNIQUE, kayit_tarihi TEXT NOT NULL, durum TEXT NOT NULL DEFAULT 'etkin' CHECK (durum IN ('etkin','askida','kapali')) ); CREATE TABLE kitap ( kitap_id INTEGER PRIMARY KEY, baslik TEXT NOT NULL, yazar TEXT NOT NULL, isbn TEXT UNIQUE, sube_id INTEGER NOT NULL REFERENCES sube(sube_id) ); CREATE TABLE odunc ( odunc_id INTEGER PRIMARY KEY, uye_id INTEGER NOT NULL REFERENCES uye(uye_id), kitap_id INTEGER NOT NULL REFERENCES kitap(kitap_id), alis_tarihi TEXT NOT NULL, iade_tarihi TEXT ); CREATE INDEX odunc_uye ON odunc(uye_id); CREATE INDEX odunc_kitap_tarih ON odunc(kitap_id, alis_tarihi); CREATE VIEW acik_odunc AS SELECT * FROM odunc WHERE iade_tarihi IS NULL; INSERT INTO sube VALUES (1,'Merkez','Ankara'),(2,'Bahçelievler','Ankara'); INSERT INTO uye (uye_id,ad,eposta,kayit_tarihi) VALUES (1,'Ayşe','[email protected]','2023-02-14'); INSERT INTO kitap VALUES (1,'Gökbilim El Kitabı','Y. Aydın','978-0201896831',1); INSERT INTO odunc VALUES (1,1,1,'2025-06-01',NULL); SQL
Şemadaki nesnelerin listesi tek bir sorguyla alınır.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT type, name, tbl_name FROM sqlite_schema ORDER BY type, name; SQL
type name tbl_name ----- ------------------------ ---------- index odunc_kitap_tarih odunc index odunc_uye odunc index sqlite_autoindex_kitap_1 kitap index sqlite_autoindex_uye_1 uye table kitap kitap table odunc odunc table sube sube table uye uye view acik_odunc acik_odunc
Listede yazılmayan iki satır dikkat çeker: sqlite_autoindex_ önekli dizinler. Bunları
tanımlayıcı yazmadı; benzersizlik kısıtını uygulayabilmek için motor kendisi oluşturdu.
Katalog, yalnız yazılanı değil motorun kurduğu yapıyı da gösterir. Bu ayrım
yönetimde işe yarar: bir sütunun benzersiz olması, arka planda bir dizin maliyeti
demektir ve o maliyet burada görünür.
Nesne adlarının önekli ayrılması bir gelenektir ve motora göre değişir; değişmeyen, iç nesnelerin de katalogda bulunmasıdır.
Envanteri Sorguyla Çıkarmak
Katalog sorgulanabilir olduğu için, şema hakkındaki her soru bir sorguya çevrilebilir. Aşağıdaki sorgu tablo başına sütun ve kısıt sayımını üretir.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column -- Sema envanteri: tablo basina sutun ve kisit sayilari. SELECT m.name AS tablo, count(*) AS sutun, sum(ti."notnull") AS not_null, sum(ti.pk > 0) AS birincil_anahtar FROM sqlite_schema m JOIN pragma_table_info(m.name) ti WHERE m.type='table' GROUP BY m.name ORDER BY m.name; SQL
tablo sutun not_null birincil_anahtar ----- ----- -------- ---------------- kitap 5 3 1 odunc 5 3 1 sube 3 2 1 uye 5 3 1
Bu tablo bir şema tasarımı tartışmasının başlangıç noktasıdır: hangi tablo kaç sütun taşıyor, kaç sütun zorunlu, birincil anahtarı olmayan tablo var mı. Elle tutulan bir belgede bu üç soru için üç ayrı bölüm gerekir ve üçü de eskir; katalogdan çıkarıldığında sorgu her çalıştırıldığında güncel yanıtı verir.
Katalogla Yazılan Denetimler
Kataloğun asıl değeri, kuralların sorgu olarak yazılabilmesidir. Dizinler ve Bölümleme konusunda görülecek bir kuralı şimdiden uygulayalım: yabancı anahtar taşıyan her sütunun kendi dizini olmalıdır, yoksa ana tablodaki silme ve güncelleme işlemleri çocuk tabloyu baştan sona taramak zorunda kalır.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column -- 1. Yabanci anahtari dizinsiz kalan sutunlar: silme ve guncelleme maliyetini artirir. SELECT m.name AS tablo, f."from" AS sutun, f."table" AS hedef FROM sqlite_schema m JOIN pragma_foreign_key_list(m.name) f WHERE m.type = 'table' AND NOT EXISTS ( SELECT 1 FROM pragma_index_list(m.name) il JOIN pragma_index_info(il.name) ii WHERE ii.seqno = 0 AND ii.name = f."from" ); SQL
tablo sutun hedef ----- ------- ----- kitap sube_id sube
Denetim tek bir bulgu üretti: kitap tablosundaki şube başvurusu dizinsiz. Ödünç tablosundaki iki başvuru kapsanıyor — biri kendi dizinine, diğeri bileşik dizinin ilk sütunu olduğu için ona dayanıyor. Bileşik dizinin yalnız ilk sütununun bu işi gördüğü, Sorgu Başarımı konusunda kurulan kuralın buradaki karşılığıdır.
Bu denetimin elle tutulan listeye üstünlüğü üç noktadadır. Yeni bir tablo eklendiğinde denetim onu kendiliğinden kapsar. Bir dizin kaldırıldığında bulgu kendiliğinden geri gelir. Ve denetim, tanımlayıcının ne yazdığını değil motorun ne bildiğini okur — ikisi ayrıştığında ayrışma görünür olur.
Aynı kalıpla yazılabilecek başka denetimler vardır: birincil anahtarı olmayan tablolar, hiç kullanılmayan dizinler, aynı sütun listesini paylaşan yinelenen dizinler, değer denetimi olmayan durum sütunları. Her biri bir yönetim kuralının sorgu biçimidir.
Şema Sapmasının Ölçülmesi
Katalog sorgulanabilir olduğu için iki veritabanının şeması karşılaştırılabilir. Bu, sürüm yükseltmelerinde ve ortamlar arası tutarlılık denetiminde en sık ihtiyaç duyulan işlemdir.
# Iki semanin farki: gelistirme ve uretim kopyalari ayni mi? sqlite3 uretim.db <<'SQL' CREATE TABLE sube (sube_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, sehir TEXT NOT NULL); CREATE TABLE uye (uye_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, eposta TEXT UNIQUE, kayit_tarihi TEXT NOT NULL); CREATE TABLE kitap (kitap_id INTEGER PRIMARY KEY, baslik TEXT NOT NULL, yazar TEXT NOT NULL, isbn TEXT UNIQUE, sube_id INTEGER NOT NULL REFERENCES sube(sube_id)); CREATE TABLE odunc (odunc_id INTEGER PRIMARY KEY, uye_id INTEGER NOT NULL REFERENCES uye(uye_id), kitap_id INTEGER NOT NULL REFERENCES kitap(kitap_id), alis_tarihi TEXT NOT NULL, iade_tarihi TEXT); CREATE INDEX odunc_uye ON odunc(uye_id); SQL esle() { sqlite3 "$1" "SELECT type||' '||name||' ('||coalesce((SELECT group_concat(ti.name||':'||ti.type, ', ') FROM pragma_table_info(m.name) ti), '')||')' FROM sqlite_schema m WHERE name NOT LIKE 'sqlite_%' ORDER BY type, name;" } esle kutuphane.db > gelistirme.liste esle uretim.db > uretim.liste echo "--- yalniz gelistirmede olan ---" comm -23 gelistirme.liste uretim.liste echo "--- yalniz uretimde olan ---" comm -13 gelistirme.liste uretim.liste
--- yalniz gelistirmede olan --- index odunc_kitap_tarih () table uye (uye_id:INTEGER, ad:TEXT, eposta:TEXT, kayit_tarihi:TEXT, durum:TEXT) view acik_odunc (odunc_id:INTEGER, uye_id:INTEGER, kitap_id:INTEGER, alis_tarihi:TEXT, iade_tarihi:TEXT) --- yalniz uretimde olan --- table uye (uye_id:INTEGER, ad:TEXT, eposta:TEXT, kayit_tarihi:TEXT)
Fark üç kalem gösteriyor. Bir dizin ve bir görünüm yalnız geliştirme kopyasında var. Üye tablosu ise iki tarafta da var ama aynı değil: geliştirmede bir durum sütunu eklenmiş, üretimde yok. Sütun listesini karşılaştırmaya katmak bu farkı görünür kılar; yalnız nesne adları karşılaştırılsaydı iki tablo eşit sayılırdı.
Sapmanın yönü de bilgidir. Geliştirmede olup üretimde olmayan bir sütun, henüz uygulanmamış bir göç demektir. Üretimde olup geliştirmede olmayan bir nesne ise daha kaygı vericidir: doğrudan üretime yazılmış, sürüm kontrolünde karşılığı olmayan bir değişikliğe işaret eder.
Kataloğa Yazmak
Katalog okunur; elle yazılmaz. Şema değişikliği veri tanımlama deyimleriyle yapılır ve katalog güncellemesini motor üstlenir. Katalog tablolarına doğrudan yazmak — bazı motorlarda teknik olarak olanaklı olsa da — motorun iç tutarlılığını bozar: veri dosyalarındaki fiziksel düzenle katalogdaki tanım ayrışır ve bu ayrışma çoğu zaman sonraki bir okumada, tanısı zor bir hata olarak görünür.
Kuralın pratik karşılığı şudur: göçler deyimlerle yazılır ve sürüm kontrolünde durur; katalog ise bu göçlerin uygulanıp uygulanmadığını doğrulamak için okunur.
Özet
- Sistem kataloğu, şemanın tanımını tutan ve sıradan sorgularla okunabilen tablolardır; değişikliği yapan deyimin kendisi onu güncellediği için her zaman günceldir.
- Katalog yalnız yazılanı değil motorun kendiliğinden kurduğu nesneleri de gösterir: benzersizlik kısıtının arkasındaki dizin listede görünür.
- Şema hakkındaki her yönetim kuralı bir sorguya çevrilebilir; dizinsiz yabancı anahtar denetimi modelde tek bulgu üretti ve yeni tabloları kendiliğinden kapsar.
- İki kopyanın şeması sütun listeleriyle birlikte karşılaştırıldığında sapma görünür olur; yalnız nesne adları karşılaştırılırsa değişmiş bir tablo eşit sayılır.
- Katalog okunur, elle yazılmaz: şema değişikliği deyimlerle yapılır, katalog o değişikliğin uygulandığını doğrulamak için sorgulanır.
Sonraki Adım
Motorun içyapısı bu dersle tamamlanıyor: süreçler, sayfalar, günlük, denetim noktaları, sürüm zincirleri, temizlik ve bunların hepsini kayda geçiren katalog. Bu bölümde bir bulgu askıda kaldı — dizinsiz yabancı anahtar. Sonraki konu bu bulgunun ait olduğu alanı açar: dizin türlerinin birbirinden farkı, bileşik dizinde sütun sırasının neden sonucu değiştirdiği, kısmi ve kapsayan dizinlerin ne zaman kazandırdığı ve bir tablonun bölümlere ayrılmasının hangi sorunu çözüp hangisini doğurduğu.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.