// Sorgu yolundaki ifade indexi + WAL bakımı. refresh sonrası (ve istenince tek // başına) çalıştırılır; tekrar çalıştırmak güvenlidir. // // src/lib/db.ts tüm aralık sorgularını EFEKTIF_SIRA_SQL üzerinden yapar; // SQLite ifade indexleri METİNSEL eşleştiği için indeks ifadesi // src/lib/veri-yillari.ts'teki sabitle birebir aynı olmalıdır — bu yüzden // buraya elle yazılmaz, import edilir. Bu index olmadan her sorgu // tur-partisyonunu tarayıp temp B-tree ile sıralıyordu. // // Kullanım: pnpm db:index --db data/yokatlas.db [--vacuum] // --vacuum: arşivleme gibi büyük silmelerden sonra dosyayı küçültür (site kapalıyken). import { EFEKTIF_SIRA_SQL } from "../src/lib/veri-yillari"; import { bayrakVar, calistir, dbAc, dbArgumani, dur, type Db } from "./yokatlas-goc"; export const EFEKTIF_INDEKS = "idx_programs_tur_onlisans_efektif"; /** * Efektif sıra indeksini güncel ifadeyle kurar. Eski yılın ifadesiyle kurulmuş * aynı adlı indeks varsa DROP edip yeniden kurar (yıl değişince ifade değişir). */ export function efektifIndeksiKur(db: Db): "kuruldu" | "yenilendi" | "guncel" { const mevcut = db .prepare("SELECT sql FROM sqlite_master WHERE type = 'index' AND name = ?") .get(EFEKTIF_INDEKS) as { sql: string } | undefined; let sonuc: "kuruldu" | "yenilendi" | "guncel" = "kuruldu"; if (mevcut) { if (mevcut.sql.includes(EFEKTIF_SIRA_SQL)) return "guncel"; db.exec(`DROP INDEX ${EFEKTIF_INDEKS}`); sonuc = "yenilendi"; } db.exec( `CREATE INDEX ${EFEKTIF_INDEKS} ON programs (tur, onlisans, ${EFEKTIF_SIRA_SQL})` ); return sonuc; } /** Sihirbaz/liste aralık sorgusunun planı (src/lib/db.ts dilimAra ile aynı biçim). */ export function efektifSorguPlani(db: Db): string[] { const plan = db .prepare( `EXPLAIN QUERY PLAN SELECT id FROM programs WHERE tur = ? AND onlisans = ? AND ${EFEKTIF_SIRA_SQL} IS NOT NULL AND ${EFEKTIF_SIRA_SQL} BETWEEN ? AND ? ORDER BY ${EFEKTIF_SIRA_SQL} ASC LIMIT 10` ) .all("SAYISAL", 0, 1000, 50000) as { detail: string }[]; return plan.map((p) => p.detail); } if (process.argv[1]?.endsWith("db-index.ts")) { calistir(() => { const db = dbAc(dbArgumani()); console.log(`Efektif indeks (${EFEKTIF_SIRA_SQL}): ${efektifIndeksiKur(db)}`); // Programatik SEO sayfaları (src/lib/katalog.ts) bölüm/üniversite // detaylarını ham ada birebir IN (...) eşleşmesiyle çeker; bu iki index // olmadan her sayfa tam tablo taraması yapar. db.exec(` CREATE INDEX IF NOT EXISTS idx_programs_isim ON programs (isim); CREATE INDEX IF NOT EXISTS idx_programs_universite ON programs (universite); `); if (bayrakVar("vacuum")) { db.exec("VACUUM"); console.log("VACUUM tamam."); } // Uygulama DB'yi readonly açtığı için checkpoint yapamaz; şişen WAL'i // (okuma başına ekstra maliyet) burada dosyaya geri yaz ve sıfırla. db.pragma("wal_checkpoint(TRUNCATE)"); const plan = efektifSorguPlani(db); console.log("Sorgu planı:"); for (const satir of plan) console.log(` ${satir}`); db.close(); if (!plan.some((s) => s.includes(EFEKTIF_INDEKS))) { dur(`Sorgu planı ${EFEKTIF_INDEKS} indeksini kullanmıyor.`); } }); }