Как оптимизировать этот SQL-запрос с разницей во времени? - PullRequest
1 голос
/ 17 марта 2011

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

"Какие наиболее типичные события происходят в течение семи дней после друг друга?"

Я мог бы сделать это, используя SQL и Java-программу, просматривая каждую строку и выполняя запрос, который просматривает все события на семь дней раньше или позже, но это не очень элегантно, и производительность будет ужасной.

Я также получил помощь от JNK и Милена А. Радева для написания следующего SQL.Моя проблема в том, что когда я тестировал это на 23 миллионах строк, он работал в течение двух часов и останавливался, потому что мой RamDisk (где я запускаю базу данных PostgreSQL) был полон.Ты хоть представляешь, как я могу оптимизировать такой запрос?

SELECT a.eventID, b.eventID, COUNT(*)
FROM table a
INNER JOIN table b
    ON a.eventID <> b.eventID
WHERE aBS(EXTRACT(EPOCH FROM (a.thetimeanddate - b.thetimeanddate))) < 5 
GROUP BY a.eventID, b.eventID 
ORDER BY COUNT(*) DESC
LIMIT 1000;

1 Ответ

5 голосов
/ 17 марта 2011

Частично проблема заключается в том, что некоторые функции не позволяют СУБД выводить определенные свойства вашего запроса и затем выполнять поиск по любым индексам.(Смотрите SARGABLE для получения дополнительной информации об этом.)

Это означает, что СУБД должна обрабатывать каждую комбинацию событий и проверять вызов WHERE, чтобы убедиться, что они находятся в пределах 5 дней друг от друга.Каждая комбинация соответствует 529 000 000 000 000 комбинаций.(529 миллионов миллионов - это довольно много.)

Если вы измените запрос, указав: «ГДЕ b.thetimeanddate обладает этими свойствами», то вы можете обнаружить повышение производительности.Это произойдет, если у вас есть индекс, охватывающий поле [thetimeanddate].Например ...

SELECT
  a.eventID,
  b.eventID,
  COUNT(*)
FROM
  table a
INNER JOIN
  table b
    ON a.eventID <> b.eventID
WHERE
      b.thetimeanddate >= date_trunc('day', a.thetimeanddate) - INTERVAL '5 days'
  AND b.thetimeanddate <  date_trunc('day', a.thetimeanddate) + INTERVAL '6 days'
GROUP BY
  a.eventID,
  b.eventID
ORDER BY
  COUNT(*) DESC
LIMIT
  1000
;

СУБД теперь должна иметь возможность гораздо проще использовать любой индекс в таблице, который охватывает поле [thetimeanddate].Теперь он просто определяет усеченные даты для каждого из 29 миллионов событий, которые у вас есть, и проверяет индекс, чтобы увидеть, сколько из них появляется между «этой датой» и «этой датой».Вполне возможно, в несколько миллионов раз быстрее, чем альтернатива ...

(Я также хотел бы переместить предложение WHERE в предложение ON, но только в целях стиля. Производительность будет идентичной. Помните, чтоRBDMS компилирует эти запросы и выбирает алгоритмы и оптимизации. Если два запроса можно алгебраически манипулировать так, чтобы они были одинаковыми, они, как правило, приводят к одному и тому же плану окончательного выполнения.не «просто известно в вашей голове».])

РЕДАКТИРОВАТЬ

Я также заметил, что вы группируете по a.eventID и b.eventID,затем делать подсчет.Если предположить, что идентификатор события уникален в таблице, это всегда будет иметь счет 1 ...

РЕДАКТИРОВАТЬ

Изменено +5 на + ИНТЕРВАЛ '5 дней'

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