(AKA - с запросом и данными, очень похожими на вопрос " Выбор строк, упорядоченных по одному столбцу и различающихся по другому ", как я могу заставить его работать быстро). Postgres 11.
У меня есть таблица prediction
с (article_id, prediction_date, predicted_as, article_published_date)
, которая представляет выходные данные классификатора для набора статей.
Новые статьи часто добавляются в отдельную таблицу (представлена FK article_id
), а новые прогнозы добавляются по мере настройки нашего классификатора.
Пример данных:
| id | article_id | predicted_as | prediction_date | article_published_date
| 1009381 | 362718 | negative | 2018-07-27 | 2018-06-26
| 1009382 | 362718 | positive | 2018-08-12 | 2018-06-26
| 1009383 | 362719 | positive | 2018-08-13 | 2010-09-22
| 1009384 | 362719 | positive | 2018-09-28 | 2010-09-22
| 1009385 | 362719 | negative | 2018-10-01 | 2010-09-22
Сценарий создания таблицы:
create table prediction
(
id serial not null
constraint prediction_pkey
primary key,
article_id integer not null
constraint prediction_article_id_fkey
references article,
predicted_as classifiedas not null,
prediction_date date not null,
article_published_date date not null
);
create index prediction_article_id_prediction_date_idx
on prediction (article_id asc, prediction_date desc);
Мы часто хотим просмотреть самую последнюю классификацию для каждой статьи. Для этого мы используем:
SELECT DISTINCT ON (article_id) article_id, id, article_published_date
FROM prediction
ORDER BY article_id, prediction_date desc
, который возвращает что-то вроде:
| id | article_id | predicted_as | prediction_date | article_published_date
| 120950 | 1 | negative | 2018-06-29 | 2018-03-25
| 120951 | 2 | negative | 2018-06-29 | 2018-03-19
При индексе (article_id, prediciton_date desc)
этот запрос выполняется очень быстро (~ 15 мс). Это план объяснения:
Unique (cost=0.56..775374.53 rows=1058394 width=20)
-> Index Scan using prediction_article_id_prediction_date_id_idx on prediction (cost=0.56..756071.98 rows=7721023 width=20)
Пока все хорошо.
Проблема возникает, когда я хочу отсортировать этот результат по элементу article_published_field. Например:
explain (analyze, buffers)
select *
from (
select distinct on (article_id) article_id, id, article_published_date
from prediction
order by article_id, prediction_date desc
) most_recent_predictions
order by article_published_date desc
limit 3;
Это работает, но выполнение запроса занимает ~ 3-4 секунды, что делает его слишком медленным для непосредственного ответа на веб-запрос.
Вот план объяснения:
Limit (cost=558262.52..558262.53 rows=3 width=12) (actual time=4748.977..4748.979 rows=3 loops=1)
Buffers: shared hit=7621849 read=9051
-> Sort (cost=558262.52..560851.50 rows=1035593 width=12) (actual time=4748.975..4748.976 rows=3 loops=1)
Sort Key: most_recent_predictions.article_published_date DESC
Sort Method: top-N heapsort Memory: 25kB
Buffers: shared hit=7621849 read=9051
-> Subquery Scan on most_recent_predictions (cost=0.43..544877.67 rows=1035593 width=12) (actual time=0.092..4508.464 rows=1670807 loops=1)
Buffers: shared hit=7621849 read=9051
-> Result (cost=0.43..534521.74 rows=1035593 width=16) (actual time=0.092..4312.916 rows=1670807 loops=1)
Buffers: shared hit=7621849 read=9051
-> Unique (cost=0.43..534521.74 rows=1035593 width=16) (actual time=0.090..4056.644 rows=1670807 loops=1)
Buffers: shared hit=7621849 read=9051
-> Index Scan using prediction_article_id_prediction_date_idx on prediction (cost=0.43..515295.09 rows=7690662 width=16) (actual time=0.089..3248.250 rows=7690662 loops=1)
Buffers: shared hit=7621849 read=9051
Planning Time: 0.130 ms
Execution Time: 4749.007 ms
Можно ли как-нибудь ускорить выполнение этого запроса, или мне придется прибегнуть к обновлению материализованного представления или настройке триггерной системы для быстрого получения этих данных?
Для справки:
- таблица
prediction
имеет 7,7M строк
- в таблице
prediction
- есть индекс на
(article_id, prediciton_date desc)
и индекс на article_published_date desc
VACUUM ANALYSE
запущено