47 lines
2.7 KiB
SQL
47 lines
2.7 KiB
SQL
-- 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);
|