Я использую разделение таблиц для хранения сообщений, разбитых по месяцам. В этом месяце наш веб-сайт вышел из строя, потому что запросы на новый месяц работали очень плохо. До сих пор не знаю, почему.
Объясните запрос за предыдущий месяц (~ 200M строк)
https://explain.depesz.com/s/yGDH
Объясните для того же запроса в текущем месяце (~ 400 тыс. строк)
https://explain.depesz.com/s/g7fV
Как видно из пояснений, используется сканирование индекса (conv_id, с включенным фильтром). «создал»), а другой сначала выполняет сканирование кучи растрового изображения после сканирования индекса растрового изображения.
Структура таблицы:
CREATE TABLE conv_messages
(
conv_message_id bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 9223372036854775807 CACHE 1 ),
conv_id bigint NOT NULL,
message text COLLATE pg_catalog."default" NOT NULL,
message_type smallint NOT NULL DEFAULT 1,
created timestamp without time zone NOT NULL DEFAULT now(),
unread boolean NOT NULL DEFAULT true,
from_user_id integer NOT NULL,
CONSTRAINT convmessages_pkey PRIMARY KEY (conv_message_id, created)
) PARTITION BY RANGE (created) ;
CREATE INDEX conv_messages_unreads
ON conv_messages USING btree
(unread ASC NULLS LAST)
TABLESPACE pg_default
WHERE unread IS TRUE;
CREATE INDEX ix_convm_user_id
ON conv_messages USING btree
(from_user_id ASC NULLS LAST)
TABLESPACE pg_default;
CREATE INDEX ix_convmessages_convid
ON conv_messages USING btree
(conv_id ASC NULLS LAST)
TABLESPACE pg_default;
CREATE INDEX ix_convmessages_created
ON conv_messages USING btree
(created DESC NULLS FIRST)
TABLESPACE pg_default;
и (простой) запрос:
select * from conv_messages m
where
m.created >= '2020-03-01 00:00:00' and
m.created < '2020-04-01 00:00:00' and
m.conv_id = 259395024
order by m.created desc
limit 20 offset 0;
Я не понимаю, почему разделенная таблица с 200m + строками работает в 40 раз быстрее, чем таблица с только 400k строками, учитывая, что таблицы одинаковы. Я попытался переиндексации create_ix и conv_id_ix, но это не имело никакого значения.
Кто-нибудь знает, что здесь может происходить? Я использую postgresql 12