Gymterview
middle

Какие основные приёмы оптимизации запросов в PostgreSQL?

Оптимизация запросов — это системный процесс: сначала EXPLAIN ANALYZE для диагностики, затем точечные изменения. Восемь основных приёмов покрывают подавляющее большинство ситуаций.

1. Создание подходящих индексов

Пример
EXPLAIN ANALYZE SELECT * FROM orders WHERE customer_id = 42 AND status = 'active';
-- Если Seq Scan — создать индекс:
CREATE INDEX idx_orders_cust_status ON orders (customer_id, status);

2. Актуальность статистики

Пример
ANALYZE transactions;
-- Увеличить детализацию статистики для столбца
ALTER TABLE transactions ALTER COLUMN status SET STATISTICS 1000;
ANALYZE transactions;

3. Выбирать только нужные столбцы

Пример
-- Плохо:
SELECT * FROM transactions WHERE account_id = 100;
-- Хорошо (может использовать Index Only Scan):
SELECT id, amount, created_at FROM transactions WHERE account_id = 100;

4. Keyset pagination вместо OFFSET

Пример
SELECT * FROM transactions
WHERE account_id = 100 AND id > 1000
ORDER BY id
LIMIT 20;

5. Избегать функций на индексированных столбцах

Пример
-- Плохо (индекс не используется):
SELECT * FROM users WHERE UPPER(email) = 'USER@BANK.RU';
-- Хорошо (создать expression index):
CREATE INDEX idx_email_upper ON users (UPPER(email));

6. EXISTS вместо IN для подзапросов

Пример
-- Менее эффективно для больших подзапросов:
SELECT * FROM clients WHERE id IN (SELECT client_id FROM transactions WHERE amount > 1000000);
-- Более эффективно:
SELECT * FROM clients c WHERE EXISTS (
    SELECT 1 FROM transactions t WHERE t.client_id = c.id AND t.amount > 1000000
);

7. Параллельное выполнение запросов

Пример
SET max_parallel_workers_per_gather = 4;
-- В EXPLAIN видно: Gather -> Parallel Seq Scan

8. Материализованные представления для аналитики

Пример
CREATE MATERIALIZED VIEW mv_daily_totals AS
SELECT date(created_at) AS day, sum(amount) AS total
FROM transactions GROUP BY date(created_at);

REFRESH MATERIALIZED VIEW CONCURRENTLY mv_daily_totals;

На собеседовании: не перечисляйте все приёмы списком — расскажите алгоритм: «сначала EXPLAIN ANALYZE, смотрю Seq Scan и Rows Removed, затем добавляю индекс или переписываю запрос». Это показывает системный подход, а не заученный список.