Могу ли я повысить производительность запроса, если использую несколько подзапросов и использую их результаты в качестве условия для основного запроса? - PullRequest
0 голосов
/ 14 декабря 2018

(Прежде всего, много объяснений, фактический вопрос довольно короткий в конце поста)

Это исходная ситуация: мы разрабатываем программное обеспечение, которое запрашивает данные из баз данных 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 секунд ... неплохо.

Это подводит меня к актуальному вопросу (ам):

  1. Я мог сначала запросить подзапрос программно (15 мс) и вставить результат в основнойзапрос, опять же программно, который не должен занимать намного больше времени, чем 40 секунд, верно?
  2. Есть ли другой способ выполнить эту операцию напрямую, используя только sql?

1 Ответ

0 голосов
/ 14 декабря 2018

Ответ на вопрос 1, конечно, да, особенно если вы можете использовать что-то вроде LINQ to SQL, это будет легко.LINQ преобразует метод Contains в оператор SQL IN.

. В SQL вы можете использовать подзапрос с IN?

SELECT EmdTable."Time [ns]", AVG(EmdTable."Upper Sideband [mV]") FROM EmdTable 
WHERE EmdTable.ResultID IN (
    SELECT ResultTable."ID"
    FROM ResultTable, ShmooTable 
    WHERE 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
GROUP BY  EmdTable."Time [ns]"
...