SQL: Как повысить производительность при фильтрации строк на основе внешних данных? - PullRequest
1 голос
/ 17 августа 2010

Скажем, у меня есть схема, которая представляет иерархию фиксированной глубины, например:


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 выше?

Ответы [ 4 ]

0 голосов
/ 18 августа 2010

Я закончил тем, что пришел к более быстрому запросу, который использовал другую технику и избежал самого дорогого соединения.Это примерно в 3 раза быстрее, чем запрос, который я получил после применения всех советов в этой теме.Изменение порядка соединений привело меня к пути к его устранению (а также к самому лучшему приросту производительности), поэтому я принял этот ответ.

Запрос, с которым я сейчас собираюсь работать:вложенный запрос.

0 голосов
/ 17 августа 2010

Быстрый трюк для внутренних объединений: SMALL_TABLE INNER JOIN BIG_TABLE быстрее обратного.

В вашем случае попробуйте добавить таблицу уровня 2 последним.

0 голосов
/ 17 августа 2010

Вы пытались изменить

CREATE INDEX level2_level1_id ON level2 (level1_id)

на

CREATE INDEX level2_level1_id ON level2 (level1_id, is_important)?

0 голосов
/ 17 августа 2010

Я предлагаю взглянуть на планы двух запросов (отфильтрованных и нефильтрованных), чтобы понять, почему нефильтрованный запрос такой медленный.Чистая догадка, но если в столбцах идентификаторов каждой таблицы есть только индексы, то база данных может принять решение выполнить последовательный обход таблицы level2, чтобы найти те строки, в которых IS_IMPORTANT = 1.

.попробуйте добавить индекс для level2 (level1_id, is_important).Это помещает все столбцы, используемые в предложениях WHERE различных запросов, в индекс.Похоже, это должно помочь и по другим запросам.

Поделитесь и наслаждайтесь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...