(Прежде всего, много объяснений, фактический вопрос довольно короткий в конце поста)
Это исходная ситуация: мы разрабатываем программное обеспечение, которое запрашивает данные из баз данных sqlite истроит их на разных графиках (LineChart, BarChart, ...). Идея состоит в том, что пользователь может выбирать столбцы для осей X и Y, а также любые комбинации фильтров, и программа создаст запрос, получит данные и графикиЭто.Теперь мы хотим немного улучшить производительность запроса.Для этого я беру запрос, который программа вычисляет по случайному графику, и тестирую его в DB Browser и вижу, сколько времени это займет.Затем я пытаюсь изменить запрос вручную и посмотреть, смогу ли я улучшить время.
Для этого теста мы используем большую (для sqlite) базу данных с несколькими фильтрами (размер базы данных 1,4 Гб, около 35 миллионов строк / 6 столбцов в таблице, из которой мы хотим получить результат.
У нас есть 3 связанные таблицы EmdTable
, ShmooTable
и ResultTable
. Программное обеспечение выдает мне следующий запрос (скопированный из отладочных и удаленных символов escape-строки):
SELECT (R0), AVG(R1) FROM
(SELECT (EmdTable."Time [ns]") AS R0, (EmdTable."Upper Sideband [mV]" ) AS R1 FROM EmdTable, ResultTable, ShmooTable
WHERE EmdTable."ResultID"=ResultTable."ID"
AND ResultTable."ShmooID"=ShmooTable."ID"
AND ResultTable."CommandName"="APDU: Get PO"
AND ResultTable."Repetition"="1"
AND ResultTable."StepName"="Command"
AND ShmooTable."Hn [A/m]"="2"
AND EmdTable."Time [ns]" IS NOT NULL
AND EmdTable."Upper Sideband [mV]" IS NOT NULL)
WHERE R0 IS NOT NULL AND R1 IS NOT NULL GROUP BY R0
В браузере БД этоТребуется около 62 секунд, чтобы получить результат около 15.000 точек данных (для X и Y)
Моя идея состояла в том, чтобы сразу использовать условие фильтра в подзапросах вместо того, чтобы объединять все вместе и создавать условия.Затем запрос выглядел так:
SELECT (R0), AVG(R1) FROM
(
(SELECT (EmdTable."Time [ns]") AS R0, (EmdTable."Upper Sideband [mV]" ) AS R1, (EmdTable."ResultID") AS ID1 FROM EmdTable) AS emdquery INNER JOIN
(
SELECT ID2 FROM
(SELECT ResultTable.ID AS ID2, ShmooID FROM ResultTable WHERE ResultTable."CommandName"="APDU: Get PO" AND ResultTable."Repetition"="1" AND ResultTable."StepName"="Command" ) AS resultquery INNER JOIN
(SELECT ShmooTable.ID FROM ShmooTable WHERE ShmooTable."Hn [A/m]" = "2") AS shmooquery ON resultquery.ShmooID = shmooquery.ID
) AS subquery ON emdquery.ID1 = subquery.ID2
)WHERE R0 IS NOT NULL AND R1 IS NOT NULL GROUP BY R0
Теперь вот: это занимает всего около 60 секунд ... так что не совсем улучшения производительности, на которые я надеялся.
Однако «подзапрос» наего собственный (тот, что в большом запросе выше) занимает всего около 15 мс и возвращает только 3. Если я теперь использую эти три значения напрямую, чтобы запросить мои результаты из EmdTable
liКе это:
SELECT EmdTable."Time [ns]", AVG(EmdTable."Upper Sideband [mV]") FROM EmdTable
WHERE (EmdTable.ResultID = 1102 OR EmdTable.ResultID = 4818 OR EmdTable.ResultID = 8510) AND EmdTable."Time [ns]" IS NOT NULL AND EmdTable."Upper Sideband [mV]" IS NOT NULL
GROUP BY EmdTable."Time [ns]"
Для тех же результатов, что и в первых двух запросах, «потребуется» всего около 40 секунд.Улучшение за 20 секунд ... неплохо.
Это подводит меня к актуальному вопросу (ам):
- Я мог сначала запросить подзапрос программно (15 мс) и вставить результат в основнойзапрос, опять же программно, который не должен занимать намного больше времени, чем 40 секунд, верно?
- Есть ли другой способ выполнить эту операцию напрямую, используя только sql?