Один из наших запросов PostgreSQL начал медленно (~ 15 секунд), поэтому мы посмотрели на перенос в базу данных Graph. Ранние тесты показывают значительно более высокие скорости, поэтому УДИВИТЕЛЬНЫЕ.Оптимизация медленного запроса postgresql для нескольких таблиц
Вот проблема: нам по-прежнему необходимо сохранить резервную копию данных в Postgres для нужд без аналитики. База данных Graph предназначена только для аналитики, и мы предпочли бы, чтобы она оставалась вторичным хранилищем данных. Поскольку во время этой миграции наша бизнес-логика изменилась довольно сильно, две существующие таблицы превратились в 4 - и текущая «резервная копия» выбирает в Postgres, отнимает от 1 до 6 минут для запуска.
Я пробовал несколько способов оптимизировать это, и лучше всего, кажется, превратить это в два запроса. Если кто-то может предложить очевидные ошибки здесь, я хотел бы услышать предложение. Я попытался включить левое/правое/внутреннее соединение с небольшой разницей в планировщике запросов. Порядок соединения влияет на разницу; Я думаю, что я просто не понимаю это правильно.
Я подробно рассмотрю.
Цель: Получить последние 10 вложения, отправленные к данному лицу
Структура базы данных:
CREATE TABLE message (
id SERIAL PRIMARY KEY NOT NULL ,
body_raw TEXT
);
CREATE TABLE attachments (
id SERIAL PRIMARY KEY NOT NULL ,
body_raw TEXT
);
CREATE TABLE message_2_attachments (
message_id INT NOT NULL REFERENCES message(id) ,
attachment_id INT NOT NULL REFERENCES attachments(id)
);
CREATE TABLE mailings (
id SERIAL PRIMARY KEY NOT NULL ,
event_timestamp TIMESTAMP not null ,
recipient_id INT NOT NULL ,
message_id INT NOT NULL REFERENCES message(id)
);
Sidenote: причина, почему тариф абстрагируется от сообщения в том, что тариф часто имеет более один получатель/и/одно сообщение может выходить нескольким получателям
Этот запрос занимает около 5 минут на относительно небольшом наборе данных (время планировщика запросов представляет собой комментарий выше каждого элемента):
-- 159374.75
EXPLAIN ANALYZE SELECT attachments.*
FROM attachments
JOIN message_2_attachments ON attachments.id = message_2_attachments.attachment_id
JOIN message ON message_2_attachments.message_id = message.id
JOIN mailings ON mailings.message_id = message.id
WHERE mailings.recipient_id = 1
ORDER BY mailings.event_timestamp desc limit 10 ;
Расщепление его на 2-запросов только занимает 1/8 времени:
-- 19123.22
EXPLAIN ANALYZE SELECT message_2_attachments.attachment_id
FROM mailings
JOIN message ON mailings.message_id = message.id
JOIN message_2_attachments ON message.id = message_2_attachments.message_id
JOIN attachments ON message_2_attachments.attachment_id = attachments.id
WHERE mailings.recipient_id = 1
ORDER BY mailings.event_timestamp desc limit 10 ;
-- 1.089
EXPLAIN ANALYZE SELECT * FROM attachments WHERE id IN (results of above query)
Я попытался переписывания запросов несколько раз - разные порядки соединения, различные типы объединений и т. д. Я не могу представить, что это почти так же эффективно в одном запросе, как и в двух случаях.
ОБНОВЛЕНО Github имеет лучшее форматирование, так что полный выход объяснить здесь - https://gist.github.com/jvanasco/bc1dd38ca06e52c9a090
Вы также можете опубликовать вывод EXPLAIN? –
Спасибо. Я добавил его в github gist. –