Скажем, у меня есть схема, которая представляет иерархию фиксированной глубины, например:
CREATE TABLE level0 (
id INTEGER PRIMARY KEY AUTOINCREMENT,
text TEXT NOT NULL
)
CREATE TABLE level1 (
id INTEGER PRIMARY KEY AUTOINCREMENT,
text TEXT NOT NULL,
level0_id INTEGER NOT NULL
)
CREATE TABLE level2 (
id INTEGER PRIMARY KEY AUTOINCREMENT,
text TEXT NOT NULL,
level1_id INTEGER NOT NULL,
is_important INTEGER
)
CREATE INDEX level2_level1_id ON level2 (level1_id)
CREATE INDEX level1_level0_id ON level1 (level0_id)
(Просто чтобы дать представление о масштабе, предположим, что 1000 строк на уровне 0, 2000 на уровне 1 и 20000 на уровне 2 и это база данных sqlite на SD-карте телефона. Запросы уровня 0 возвращают до 1000 строк, запросы уровня 1 возвращают 1 -30 строк, а запросы уровня 2 возвращают 1-20 строк)
Я показываю эту иерархию по одному уровню за раз. Поэтому мои запросы на отображение каждого из трех уровней выглядят так:
SELECT id,text FROM level0
SELECT id,text FROM level1 WHERE level0_id = 12345
SELECT id,text FROM level2 WHERE level1_id = 23456
Простой, быстрый и полностью проиндексированный. Теперь я также хочу отобразить ту же иерархию, за исключением того, что я хочу фильтровать ее на основе is_important. Я хочу отображать только строки уровня 0 и уровня 1, которые в конечном итоге приводят к строкам уровня 2 с is_important = 1.
Поэтому я пишу несколько новых запросов, сильно отличающихся от старых.
level 0:
SELECT DISTINCT l0.id,l0.text
FROM level2 AS l2
INNER JOIN level1 AS l1 ON l1.id = l2.level1_id
INNER JOIN level0 as l0 on l0.id = l1.level0_id
WHERE l2.is_important = 1
level 1:
SELECT DISTINCT l1.id,l1.text
FROM level2 AS l2
INNER JOIN level1 AS l1 ON l1.id = l2.level1_id
WHERE l2.is_important = 1
level 2:
SELECT id,text FROM level2 WHERE level1_id = 23456 AND is_important = 1
Запросы уровня 0 и уровня 1, очевидно, намного, намного медленнее, чем запросы без фильтрации выше. Я понимаю, почему они работают медленно, но у меня возникают проблемы с улучшением их производительности.
Мне странно начинать запрос с обхода самой большой таблицы, чтобы извлечь меньшие, но это кажется самым лаконичным и естественным способом выразить то, что я хочу, в терминах, понятных для SQL.
Итак, мой вопрос таков: как бы вы улучшили производительность отфильтрованных запросов уровня 0 и уровня 1 выше?