Справочная информация : у меня есть таблица, содержащая записи финансовых транзакций.Таблица содержит несколько десятков миллионов строк для десятков тысяч пользователей.Мне нужно получить сумму транзакций для отображения балансов и других аспектов сайта.
Мой текущий запрос может быть очень медленным и часто задерживается.Я пытался оптимизировать запрос, но не могу заставить его работать эффективно.
Среда : Мое приложение работает на Heroku с использованием плана Postgres Standard-2 (оперативная память 8 ГБ, 400максимальное количество подключений, 256 ГБ разрешенного хранилища).Максимальное количество подключений в любой момент времени - около 20, а мой текущий размер БД - 35 ГБ.Согласно статистике, этот запрос выполняется в среднем около 1000 мс и используется очень часто, что сильно влияет на производительность сайта.
Для базы данных частота обращений к кешу индекса составляет 99%, а частота обращений к кешу таблицысоставляет 97%.Автовакуум запускается примерно через день на основе текущих порогов.
Вот мои текущие настройки таблицы транзакций:
CREATE TABLE transactions (
id bigint DEFAULT nextval('transactions_id_seq'::regclass) NOT NULL,
user_id integer NOT NULL,
date timestamp without time zone NOT NULL,
amount numeric(15,2) NOT NULL,
transaction_type integer DEFAULT 0 NOT NULL,
account_id integer DEFAULT 0,
reconciled integer DEFAULT 0,
parent integer DEFAULT 0,
ccparent integer DEFAULT 0,
created_at timestamp without time zone DEFAULT now() NOT NULL
);
CREATE INDEX transactions_user_id_key ON transactions USING btree (user_id);
CREATE INDEX transactions_user_date_idx ON transactions (user_id, date);
CREATE INDEX transactions_user_ccparent_idx ON transactions (user_id, ccparent) WHERE ccparent >0;
А вот мой текущий запрос:
SELECT account_id,
sum(deposit) - sum(withdrawal) AS balance,
sum(r_deposit)-sum(r_withdrawal) AS r_balance,
sum(deposit) AS o_deposit,
sum(withdrawal) AS o_withdrawal,
sum(r_deposit) AS r_deposit,
sum(r_withdrawal) AS r_withdrawal
FROM
(SELECT t.account_id,
CASE
WHEN transaction_type > 0 THEN sum(amount)
ELSE 0
END AS deposit,
CASE
WHEN transaction_type = 0 THEN sum(amount)
ELSE 0
END AS withdrawal,
CASE
WHEN transaction_type > 0 AND reconciled=0 THEN sum(amount)
ELSE 0
END AS r_deposit,
CASE
WHEN transaction_type = 0 AND reconciled=0 THEN sum(amount)
ELSE 0
END AS r_withdrawal
FROM transactions AS t
WHERE user_id = $1 AND parent=0 AND ccparent=0
GROUP BY transaction_type, account_id, reconciled ) AS t0
GROUP BY account_id;
запрос состоит из нескольких частей.Я должен получить следующее для каждой учетной записи пользователя:
1) общий остаток на счете
2) баланс для всех выверенных транзакций
3) отдельно,сумма всех депозитов, снятий, сверенных депозитов и согласованных снятий.
Вот один план запроса, когда я запускаю explain analyze
для запроса:
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------------------
HashAggregate (cost=13179.85..13180.14 rows=36 width=132) (actual time=1326.200..1326.204 rows=6 loops=1)
Group Key: t.account_id
-> HashAggregate (cost=13179.29..13179.58 rows=36 width=18) (actual time=1326.163..1326.171 rows=16 loops=1)
Group Key: t.transaction_type, t.account_id, t.reconciled
-> Bitmap Heap Scan on transactions t (cost=73.96..13132.07 rows=13491 width=18) (actual time=17.410..1317.863 rows=12310 loops=1)
Recheck Cond: (user_id = 1)
Filter: ((parent = 0) AND (ccparent = 0))
Rows Removed by Filter: 2
Heap Blocks: exact=6291
-> Bitmap Index Scan on transactions_user_id_key (cost=0.00..73.29 rows=13601 width=0) (actual time=15.901..15.901 rows=12343 loops=1)
Index Cond: (user_id = 1)
Planning time: 0.895 ms
Execution time: 1326.424 ms
Есть ли у кого-нибудь какие-либо предложения о том, какускорить этот запрос?Как я уже сказал, это самый запущенный запрос в моем приложении, а также один из самых требовательных к БД.Если бы я мог оптимизировать это, это имело бы огромные преимущества для приложения в целом.