Задача
- Семантический анализ рекомендаций по оптимизации событий ожиданий СУБД.
- Семантический анализ SQL запросов.
Инцидент производительности СУБД
Корреляция ожиданий
80% событий ожидания (диаграмма Парето)
1.1 Сводная таблица мероприятий по оптимизации ожиданий типа IO
DataFileRead DSMFillZeroWrite
Настройка памяти ✅ ✅ ✅
- work_mem ✅ ✅ ✅
- shared_buffers ✅ ✅ ✅
- maintenance_work_mem ✅ ✅ ✅
Оптимизация запросов ✅ ✅ ✅
- Анализ тяжелых запросов ✅ ✅ ✅
- Операции в памяти ✅ ✅ ✅
Управление соединениями ❌ ✅ ⚠️
- Пул соединений ❌ ✅ ⚠️
Параллельные операции ❌ ✅ ⚠️
- Контроль параллельных воркеров ❌ ✅ ⚠️
Индексы и партиционирование ✅ ❌ ⚠️
- Добавление индексов ✅ ❌ ⚠️
- Партиционирование таблиц ✅ ❌ ⚠️
Обслуживание БД ✅ ✅ ✅
- Автовакуум ✅ ✅ ✅
- VACUUM/ANALYZE ✅ ✅ ✅
Аппаратное масштабирование ✅ ❌ ⚠️
- Увеличение RAM/дисков ✅ ❌ ⚠️
Ключевые выводы:
✅ Общие обязательные мероприятия:
- Настройка памяти - критична для обоих типов ожиданий
- Оптимизация запросов - устранение операций, потребляющих много памяти
- Обслуживание БД - регулярный автовакуум и анализ
⚠️ Специфические мероприятия:
- Для DataFileRead: фокус на индексы, партиционирование и дисковую подсистему
- Для DSMFillZeroWrite: фокус на управление соединениями и параллельными операциями
🎯 Приоритетные действия:
- Настроить work_mem и shared_buffers
- Выявить и оптимизировать проблемные запросы
- Настроить автовакуум
- Внедрить пул соединений
- Оптимизировать индексы
1.2 Сводная таблица мероприятий по оптимизации ожиданий типа IPC
BgWorkerShutdown ExecuteGather ParallelFinish
Анализ и оптимизация запросов ✅ ✅ ✅ ✅
- EXPLAIN ANALYZE планов ✅ ✅ ✅ ✅
- Пересмотр необходимости параллелизма ✅ ✅ ✅ ✅
Настройка параметров параллелизма ❌ ✅ ✅ ✅
- max_parallel_workers_per_gather ❌ ✅ ✅ ✅
- parallel_setup_cost/parallel_tuple_cost ❌ ❌ ✅ ⚠️
Управление системными ресурсами ❌ ✅ ✅ ✅
- Мониторинг CPU ❌ ✅ ✅ ✅
- Мониторинг Disk I/O ❌ ✅ ✅ ✅
Настройка памяти ❌ ❌ ✅ ⚠️
- work_mem ❌ ❌ ✅ ⚠️
Обслуживание БД ✅ ❌ ✅ ✅
- Индексы для больших таблиц ✅ ❌ ❌ ⚠️
- Обновление статистики (ANALYZE) ❌ ❌ ✅ ⚠️
✅ Общие обязательные мероприятия для всех IPC-ожиданий:
- Анализ запросов - использование EXPLAIN ANALYZE для проблемных запросов
- Рациональное использование параллелизма - отключение для быстрых запросов
- Мониторинг системных ресурсов - CPU и Disk I/O
🎯 Специфические фокусы:
- BgWorkerShutdown: фокус на индексы для замены Seq Scan
- ExecuteGather: точная настройка параметров параллелизма
- ParallelFinish: комплексная оптимизация памяти и статистики
⚡ Критичные действия:
- Анализ планов выполнения проблемных запросов
- Настройка max_parallel_workers_per_gather для баланса параллелизма
- Отключение параллелизма где накладные расходы превышают выгоду
- Мониторинг загрузки CPU и диска при параллельных операциях
📊 Приоритет оптимизации:
Высокий: ExecuteGather → ParallelFinish → BgWorkerShutdown
1.3 Сводная таблица мероприятий по оптимизации ожиданий типа Lock
Мероприятия Применимость
➖➖➖
Управление транзакциями
Сокращение времени выполнения транзакций✅ Высокая
Борьба с "idle in transaction" сессиями ✅ Высокая
Включение autocommit в приложениях✅ Средняя
Оптимизация блокировок
Использование SELECT … FOR UPDATE NOWAIT ✅ Высокая
Использование SELECT … FOR UPDATE SKIP LOCKED ✅ Высокая
Пересмотр логики блокировок в приложении ✅ Высокая
Обслуживание БД
Настройка эффективного автовакуума ✅ Высокая
Своевременное удаление старых версий строк ✅ Высокая
Управление соединениями
Использование пулера соединений (PgBouncer) ✅ Средняя
Ограничение количества одновременных подключений ✅ Средняя
Мониторинг
Контроль подготовленных транзакций ✅ Средняя
Принудительное завершение старых транзакций ✅ Низкая
➖➖➖
Ключевые приоритеты оптимизации:
🚀 Критичные мероприятия (высокий приоритет):
- Сокращение длительных транзакций - основной источник блокировок
- Ликвидация "idle in transaction" сессий - частые виновники deadlock'ов
- Настройка автовакуума - предотвращение накопления старых версий строк
⚡ Тактические решения (средний приоритет):
- Использование NOWAIT/SKIP LOCKED - для неблокирующих операций
- Внедрение пулера соединений - контроль параллелизма на уровне приложения
- Регулярный мониторинг подготовленных транзакций
🛡️ Профилактические меры (низкий приоритет):
- Принудительное завершение проблемных транзакций
- Архитектурный пересмотр логики блокировок
Основной вывод:
Проблемы с блокировками типа transactionid решаются в первую очередь через оптимизацию логики работы приложения с транзакциями, а не через настройку параметров СУБД.
2.1 Семантический анализ SQL запросов вызывающих ожидания типа IO
Частота паттернов (в порядке убывания):
- SELECT с JOIN + WHERE + ORDER BY + LIMIT - 8 раз
- UPDATE с SET + WHERE - 8 раз
- SELECT с WHERE + IN - 7 раз
- SELECT с WHERE + LIMIT - 6 раз
- SELECT COUNT с WHERE - 5 раз
- SELECT с WHERE + ORDER BY + LIMIT - 4 раза
- SELECT с JOIN + WHERE + LIMIT - 1 раз
- SELECT с WHERE + сложные условия (OR) - 1 раз
- SELECT с JOIN + WHERE - 1 раз
Таблица паттернов по queryid:
Запрос с наибольшим количеством паттернов:
Query ID: -4117824125973382848
SELECT "user_profile_userprofile"."id", ...
FROM "user_profile_userprofile"
INNER JOIN "users_user" ON ("user_profile_userprofile"."user_id" = "users_user"."id")
WHERE "user_profile_userprofile"."external_id" IN ($1)
Ключевые особенности:
- Сложный JOIN между таблицами пользователей и профилей
- Условие WHERE с IN для фильтрации по external_id
- Выборка большого количества полей (более 50 колонок)
- Отсутствие LIMIT - может возвращать множественные записи
- Использование плейсхолдеров ($1) для параметризации запроса
Этот запрос демонстрирует наиболее комплексный подход к получению данных о пользователях, объединяя информацию из профиля и основных данных пользователя с фильтрацией по внешним идентификаторам.
2.2 Семантический анализ SQL запросов вызывающих ожидания типа IPC
Частота паттернов:
- SELECT с JOIN + WHERE + ORDER BY + LIMIT - 5 раз (83%)
- SELECT COUNT с WHERE - 1 раз (17%)
Таблица паттернов по queryid:
Ключевые особенности запросов с паттерном JOIN:
Все 5 запросов имеют идентичную логику, но работают с разными таблицами:
SELECT [множество полей]
FROM [users_user|auth_user]
INNER JOIN "keycloak_userprofilekeycloak"
ON ([user_table]."id" = "keycloak_userprofilekeycloak"."user_id")
WHERE ([user_table]."is_superuser"
AND "keycloak_userprofilekeycloak"."keycloak_roles"::text LIKE '%superuser%')
ORDER BY [user_table]."id" [ASC|DESC]
LIMIT 1
Общие характеристики:
- Двойная проверка суперпользователя - через поле is_superuser и через наличие 'superuser' в keycloak_roles
- INNER JOIN между основной таблицей пользователей и keycloak профилем
- LIMIT 1 - всегда возвращает только одну запись
- Сортировка по ID пользователя (ASC или DESC)
- Выборка большого количества полей из обеих таблиц
Различия:
- Используются разные таблицы: users_user (2 раза) и auth_user (3 раза)
- Направление сортировки: преимущественно ASC (4 из 5), один раз DESC
Этот паттерн используется для получения информации о суперпользователе системы с проверкой через Keycloak аутентификацию.
2.3 Семантический анализ SQL запросов вызывающих ожидания типа Lock
Частота паттернов:
- UPDATE с SET + WHERE - 2 раза (100%)
Таблица паттернов по queryid:
Ключевые особенности:
Оба запроса имеют одинаковую структуру:
UPDATE "table_name"
SET "field1" = $1, "field2" = $2
WHERE "table_name"."primary_key" = $3
Общие характеристики:
- Параметризованные запросы - использование плейсхолдеров ($1, $2, $3)
- Точечное обновление - WHERE условие по первичному ключу
- Простая структура - без подзапросов, JOIN или сложных условий
Различия:
- 3767433716548860436 - обновляет два поля (info, user_info) в таблице расширений пользователя по user_id
- 1934896262595455255 - обновляет одно поле (roles_and_permissions_as_dict) в Keycloak профиле по id
Так как оба запроса используют одинаковое количество паттернов (по одному), можно выделить, что:
Запрос 3767433716548860436 имеет особенность - он обновляет два поля одновременно, что может быть связано с атомарным обновлением связанных данных в пользовательском расширении. Оба запроса являются типичными операциями обновления данных с минимальной блокировкой, что соответствует событию "Lock".