-- Die Projektzugehörigkeit auch in den Nebentabellen führen. -- -- ── Warum? ─────────────────────────────────────────────────────────────────── -- -- Bisher stand project_id nur an "entries". Wer die Schlagworte eines Projekts -- zählen wollte, musste deshalb über entries verbinden: -- -- SELECT t.tag, COUNT(*) FROM entry_tags t -- JOIN entries e ON e.id = t.entry_id -- WHERE e.project_id = ? GROUP BY t.tag -- -- SQLite läuft dafür durch ALLE Einträge des Projekts und schlägt zu jedem die -- Schlagworte nach — der Aufwand wächst also mit der Zahl der Einträge, obwohl -- am Ende nur ein paar Dutzend Schlagworte herauskommen. Gemessen bei 5.000 -- Einträgen: 6,7 ms. Seit die Schlagworte in der Seitenleiste stehen, läuft -- diese Abfrage bei JEDEM Seitenaufruf. -- -- Dasselbe bei den Rückverweisen: Dort kippte zusätzlich die Reihenfolge der -- Verknüpfung, sobald ein ORDER BY dazukam — statt vom kleinen Verweis-Index -- auszugehen, lief SQLite wieder durch alle Einträge (3,1 ms statt 9 µs). -- -- ── Der Handel ─────────────────────────────────────────────────────────────── -- -- Eine Spalte doppelt zu führen ist eine Redundanz, und Redundanz kann -- auseinanderlaufen. Hier ist das vertretbar: Beide Tabellen werden -- ausschließlich in replaceTags/replaceLinks geschrieben, innerhalb derselben -- Transaktion wie der Eintrag selbst. Es gibt keinen zweiten Schreibweg. -- ALTER TABLE ... ADD COLUMN können SQLite und PostgreSQL gleichermaßen. -- NOT NULL braucht dabei einen Vorgabewert, sonst wüssten bestehende Zeilen -- nicht, was hineingehört. ALTER TABLE entry_tags ADD COLUMN project_id TEXT NOT NULL DEFAULT ''; UPDATE entry_tags SET project_id = (SELECT e.project_id FROM entries e WHERE e.id = entry_tags.entry_id); ALTER TABLE entry_links ADD COLUMN project_id TEXT NOT NULL DEFAULT ''; UPDATE entry_links SET project_id = (SELECT e.project_id FROM entries e WHERE e.id = entry_links.from_entry_id); -- Die alten Indizes werden nicht mehr gebraucht: Jede Abfrage kennt jetzt das -- Projekt und kann den zusammengesetzten Index nutzen. DROP INDEX idx_entry_tags_tag; DROP INDEX idx_entry_links_to; -- project_id zuerst, dann das eigentliche Suchmerkmal: So deckt der Index -- sowohl "alle Schlagworte eines Projekts" als auch "ein bestimmtes Schlagwort -- in einem Projekt" ab. CREATE INDEX idx_entry_tags_projekt ON entry_tags (project_id, tag); CREATE INDEX idx_entry_links_projekt ON entry_links (project_id, to_slug);