оптимизация SQL-запроса с несколькими минимальными и максимальными диапазонами - PullRequest
0 голосов
/ 15 декабря 2018

У меня большие проблемы с оптимизацией SQL-запроса, который требует возрастов для запуска набора данных с ~ 300 000 строк.

Я выполняю запрос к таблице stat_records с десятичной дробьюvalue и столбец datetime recorded_at.

Я хочу узнать значения MAX и MIN в любом из следующих периодов: все время, в прошлом году, последние 6 месяцев, последние 3 месяца, последний месяц, последние 2 недели.

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

SELECT MIN("stat_records"."value")
FROM "stat_records"
   INNER JOIN "stats" ON "stats"."id" = "stat_records"."stat_id"
WHERE "stat_records"."object_id" = $1
  AND "stats"."identifier" = $2
  AND ("stat_records"."recorded_at" BETWEEN $3 AND $4)

[["object_id", 1],
 ["identifier", "usd"],
 ["recorded_at", "2018-10-15 20:10:58.418512"],
 ["recorded_at", "2018-12-15 20:11:59.351437"]]

Определение таблицы:

create_table "stat_records", force: :cascade do |t|
  t.datetime "recorded_at"
  t.decimal "value"
  t.bigint "coin_id"
  t.bigint "object_id"
  t.index ["object_id"], name: "index_stat_records_on_object_id"
  t.index ["recorded_at", "object_id", "stat_id"], name: "for_upsert", unique: true
  t.index ["recorded_at", "stat_id"], name: "index_stat_records_on_recorded_at_and_stat_id", unique: true
  t.index ["recorded_at"], name: "index_stat_records_on_recorded_at"
  t.index ["stat_id"], name: "index_stat_records_on_stat_id"
  t.index ["value"], name: "index_stat_records_on_value"
end

Этот подход,однако, требуется навсегда, чтобы завершить.У меня есть индексы для таблицы stat_records в столбцах value и recorded_at.

Чего мне здесь не хватает - что мне следует сделать, чтобы оптимизировать это?

Возможно, есть некоторыелучше подходить так, чтобы я мог выполнить 1 запрос и позволить postgres выполнить оптимизацию для меня.

1 Ответ

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

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

Ваше решение может быть материализованным представлением.Таким образом, вы можете предварительно агрегировать значения, и полученная таблица будет намного меньше, так что запросы будут выполняться быстрее.Недостатком является то, что материализованное представление должно регулярно обновляться и содержать между собой немного устаревшие данные.

Пример:

CREATE MATERIALIZED VIEW stats_per_month AS
SELECT stat_records.object_id, 
       stats.identifier
       date_trunc('month', stat_records.recorded_at) AS recorded_month,
       min(stat_records.value) AS minval
FROM stat_records
   INNER JOIN stats ON stats.id = stat_records.stat_id
GROUP BY stat_records.object_id, 
         stats.identifier
         date_trunc('month', stat_records.recorded_at);

Если вам нужна месячная детализация для вашего запроса, вы просто запрашиваетеиз материализованного представления, а не из исходных таблиц.

Вы также можете использовать гибридное решение и использовать исходный запрос для небольших диапазонов, где устаревшие данные могут повредить больше.Это должно быть быстро с индексом на recorded_at.

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