Найти в Дзене
Postgres DBA

⬆️3️⃣Оптимизация SQL-запроса с использованием pg_expecto: Часть-3 "Частичная агрегация"

Не верь на слово, проверь под давлением. Методология исследования Тестовая среда и инструменты: СУБД: PostgreSQL 17 Инструмент нагрузочного тестирования: pg_expecto Тестовая база данных: "Демобаза 2.0" (большой размер, сложная схема) Условия тестирования: параллельная нагрузка, ресурсоемкий запрос Нагрузка на СУБД 1️⃣Эксперимент-1 : Оптимизация с использованием EXISTS 2️⃣Эксперимент-2 : Оптимизация структуры запроса 3️⃣Эксперимент-3 : Частичная агрегация Тестовый запрос -ARRAY План выполнения тестового запроса -ARRAY Сравнительный анализ планов выполнения запросов ❓Проведи сравнительный анализ и сформируй итог по планам выполнения тестовых запросов TEST-1 "JOIN" (59.15 секунд) Преимущества: Более простое планирование (37.5 мс) Эффективное использование индексов (Index Only Scan) Меньше операций с диском при сортировке (121832 kB) Недостатки: Длительное время выполнения Большое количество строк для обработки (2.3M планируемых, 1.1M фактических) Сложная цепочка соединений TEST-
Оглавление
Не верь на слово, проверь под давлением.
Не верь на слово, проверь под давлением.

Методология исследования

Тестовая среда и инструменты:

Нагрузка на СУБД

-2

1️⃣Эксперимент-1 : Оптимизация с использованием EXISTS

2️⃣Эксперимент-2 : Оптимизация структуры запроса

3️⃣Эксперимент-3 : Частичная агрегация

Тестовый запрос -ARRAY

Тестовый запрос -ARRAY WITH random_period AS (   SELECT    start_date,    start_date + INTERVAL '30 days' AS end_date   FROM (    SELECT    book_date AS start_date    FROM bookings    WHERE book_date <= (SELECT MAX(book_date) FROM bookings) - INTERVAL '30 days'    ORDER BY RANDOM()    LIMIT 1   ) AS random_date ) SELECT   b.book_ref,   b.book_date,   t.ticket_no,   t.passenger_name,   s.flight…
Postgres DBA30 ноября

План выполнения тестового запроса -ARRAY

--План выполнения тестового запроса -ARRAY  Sort (cost=602598.54..603774.42 rows=470349 width=80) (actual time=32916.398..33173.216 rows=1078047 loops=1)   Sort Key: b.book_date, tn.ticket_no   Sort Method: external merge Disk: 78992kB   CTE random_period    -> Limit (cost=191879.84..191879.84 rows=1 width=24) (actual time=4366.534..4366.546 rows=1 loops=1)    -> Sort (cost…
Postgres DBA30 ноября

Сравнительный анализ планов выполнения запросов

❓Проведи сравнительный анализ и сформируй итог по планам выполнения тестовых запросов

TEST-1 "JOIN" (59.15 секунд)

Преимущества:

  • Более простое планирование (37.5 мс)
  • Эффективное использование индексов (Index Only Scan)
  • Меньше операций с диском при сортировке (121832 kB)

Недостатки:

  • Длительное время выполнения
  • Большое количество строк для обработки (2.3M планируемых, 1.1M фактических)
  • Сложная цепочка соединений

TEST-4 "ARRAY" (33.27 секунд)

Преимущества:

  • В 1.8 раза быстрее основного запроса
  • Использование параллельных вычислений (Workers Launched: 1)
  • Эффективное кэширование (Memoize с логическим кэшированием)
  • Меньше планируемых строк для обработки (470K)

Недостатки:

  • Более сложное планирование (61.1 мс)
  • Использование агрегации и развертывания массивов
  • Больше операций с памятью (28.7 MB для кэша)

Ключевые отличия в подходах

TEST-1 использует:

  • Прямые JOIN между таблицами
  • CROSS JOIN LATERAL для фильтрации по периоду
  • Последовательное соединение таблиц

TEST-4 использует:

  • Агрегацию в CTE с ARRAY_AGG
  • Развертывание массивов через UNNEST
  • Параллельную обработку
  • Логическое кэширование результатов

Итоговые выводы

  1. Архитектурное превосходство: Подход с агрегацией и массивами (TEST-4) показал значительно лучшую производительность, несмотря на более сложный план выполнения.
  2. Эффективность параллелизации: Возможность распараллеливания в TEST-4 дала существенный выигрыш в производительности.
  3. Оптимизация доступа к данным: Оба запроса эффективно используют индексы, но TEST-4 лучше справляется с увеличением объема обрабатываемых данных.
  4. Рекомендация: Для сложных аналитических запросов с агрегацией данных подход с использованием массивов и последующим развертыванием может быть более эффективным, чем традиционные JOIN, особенно при наличии возможности параллельного выполнения.

Финальный вердикт: TEST-4 демонстрирует более оптимальный подход для данного типа запросов, обеспечивая лучшую производительность за счет современных возможностей PostgreSQL.

Сравнительный анализ производительности и ожиданий СУБД в ходе нагрузочного тестирования при использовании запроса "JOIN" и запроса "ARRAY"

Операционная скорость

График изменения операционной скорости в ходе нагрузочного тестирования при использоваении тестового запроса "JOIN" и "ARRAY"
График изменения операционной скорости в ходе нагрузочного тестирования при использоваении тестового запроса "JOIN" и "ARRAY"
График изменения относительной разницы операционной скорости для запроса "ARRAY" по сравнению с тестовым запросом "JOIN"
График изменения относительной разницы операционной скорости для запроса "ARRAY" по сравнению с тестовым запросом "JOIN"

⬆️Среднее увеличение операционной скорости при использовании запроса "ARRAY" составило 120.15%

Ожидания СУБД

График изменения ожиданий СУБД в ходе нагрузочного тестирования при использоваении тестового запроса "JOIN" и "ARRAY"
График изменения ожиданий СУБД в ходе нагрузочного тестирования при использоваении тестового запроса "JOIN" и "ARRAY"
График изменения относительной разницы ожиданий СУБД для запроса "ARRAY" по сравнению с тестовым запросом "JOIN"
График изменения относительной разницы ожиданий СУБД для запроса "ARRAY" по сравнению с тестовым запросом "JOIN"
❓Проведи сравнительный анализ и сформируй итог по показаниям wait_event_type для тестовых запросов

Общая характеристика нагрузки

TEST-1 "JOIN" (более тяжелый запрос)

  • Высокая нагрузка на все подсистемы
  • Максимальные значения: IO=15183, IPC=24107, LWLOCK=106, TIMEOUT=19
  • Интенсивный рост всех показателей на протяжении выполнения

TEST-4 "ARRAY" (оптимизированный запрос)

  • Значительно меньшая нагрузка на все подсистемы
  • Максимальные значения: IO=8368, IPC=131, LWLOCK=227, TIMEOUT=5
  • Более плавный рост показателей

Детальный анализ по типам событий

1. Операции ввода-вывода (IO)

  • TEST-1: Экстремально высокие значения (до 15K), быстрый рост
  • TEST-4: В 2 раза меньше максимальная нагрузка (до 8K), более стабильный рост
  • Вывод: TEST-4 значительно эффективнее работает с диском

2. Межпроцессное взаимодействие (IPC)

  • TEST-1: Очень высокие значения (до 24K), агрессивный рост
  • TEST-4: На порядок ниже (до 131), умеренный рост
  • Вывод: TEST-1 создает большую конкуренцию за ресурсы между процессами

3. Легковесные блокировки (LWLOCK)

  • TEST-1: Высокие значения (до 106), стабильный рост
  • TEST-4: Более высокие максимальные значения (до 227), но плавный рост
  • Вывод: TEST-4 использует больше легковесных блокировок, но распределяет их лучше

4. Таймауты (TIMEOUT)

  • TEST-1: Значительное количество (до 19), указывает на ожидания
  • TEST-4: Минимальные значения (до 5)
  • Вывод: TEST-4 меньше подвержен блокировкам и ожиданиям

Ключевые выводы

Производительность и эффективность

  1. TEST-4 демонстрирует значительно лучшую эффективность использования ресурсов
  2. Меньше конкуренции за системные ресурсы (особенно IPC)
  3. Более предсказуемая нагрузка на подсистемы

Проблемные зоны TEST-1

  • Высокая конкуренция за ресурсы (IPC)
  • Интенсивные операции ввода-вывода
  • Больше времени ожидания (TIMEOUT)

Преимущества TEST-4

  • Оптимизированное использование памяти и кэширования
  • Лучшее распараллеливание работы
  • Меньше contention за системные ресурсы

Итоговый вердикт

TEST-4 "ARRAY" значительно превосходит TEST-1 "JOIN" по всем показателям wait events:

  • В 2-3 раза меньше нагрузка на IO и IPC
  • Более стабильный профиль выполнения
  • Меньше блокировок и ожиданий
  • Лучшая масштабируемость при параллельной работе

Это подтверждает выводы из анализа планов выполнения: подход с использованием массивов и агрегации более оптимален для данного типа аналитических запросов в PostgreSQL.

Сравнительный анализ метрик iostat для дискового устройства используемого файловой системой /data, в ходе нагрузочного тестирования при использовании запроса "JOIN" и запроса "ARRAY"

❓Проведи сравнительный анализ и сформируй итог по показаниям iostat для тестовых запросов в ходе нагрузочного тестирования

Оба теста демонстрируют идентичные показатели:

  • w/s: 0 (операции записи в секунду)
  • wrqm/s: 0 (запросы на запись, объединенные в очередь)
  • %wrqm: 49% (процент объединенных запросов записи)
  • w_await: 2 мс (среднее время ожидания записи)
  • wareq_sz: 10 (средний размер запроса записи)
  • %util: 0% (загрузка диска)
  • f/s: 0 (операции flush в секунду)
  • f_await: 0 (время ожидания flush)

Ключевые выводы

1. Отсутствие дисковой нагрузки

  • Оба запроса практически не создают нагрузки на систему хранения
  • Нулевые показатели операций записи и flush
  • Минимальная загрузка диска (%util = 0%)

2. Оптимизированное использование памяти

  • Все данные эффективно кэшируются в оперативной памяти
  • Отсутствие необходимости в частом обращении к диску
  • PostgreSQL эффективно использует shared_buffers

3. Сходство профилей ввода-вывода

  • Оба подхода (JOIN и ARRAY) демонстрируют одинаковые характеристики IO
  • Разница в производительности не связана с дисковой подсистемой

Связь с предыдущими анализами

В контексте wait events:

  • Высокие показатели IO wait events в предыдущем анализе не связаны с физическим IO
  • Ожидания связаны с внутренними механизмами PostgreSQL (буферы, блокировки)
  • Подтверждается эффективность кэширования данных

В контексте планов выполнения:

  • Разница в производительности объясняется вычислительной сложностью, а не IO
  • TEST-4 эффективнее использует CPU и память
  • Дисковая подсистема не является узким местом

Итоговый вердикт

Дисковая подсистема не является фактором, влияющим на разницу в производительности между запросами.

Основные выводы:

  1. Оба запроса оптимально используют кэширование - данные полностью помещаются в памяти
  2. Производительность ограничена вычислительными ресурсами (CPU, память, внутренние блокировки)
  3. Преимущество TEST-4 подтверждается в контексте эффективности использования CPU и уменьшения contention
  4. Система хранения адекватно справляется с рабочей нагрузкой

Рекомендация: Оптимизация должна быть направлена на снижение вычислительной сложности и уменьшение конкуренции за ресурсы, а не на улучшение дисковой подсистемы.

Сравнительный анализ метрик vmstat в ходе нагрузочного тестирования при использовании запроса "JOIN" и запроса "ARRAY"

❓Проведи сравнительный анализ и сформируй итог по показаниям vmstat для тестовых запросов в ходе нагрузочного тестирования

Общая характеристика системной нагрузки

TEST-1 "JOIN" (менее эффективный)

  • Высокая нагрузка на все подсистемы
  • Длительное выполнение с постепенным ростом нагрузки
  • Проблемы с управлением процессами и памятью

TEST-4 "ARRAY" (оптимизированный)

  • Более сбалансированная нагрузка
  • Эффективное использование ресурсов
  • Стабильная работа на протяжении выполнения

Детальный сравнительный анализ

1. Процессы (procs)

TEST-1:

  • procs_r: 4-9 (высокая очередь выполнения)
  • procs_b: 1-2 (постоянно есть заблокированные процессы)

TEST-4:

  • procs_r: 5-15 (умеренная очередь)
  • procs_b: 0-1 (минимальное блокирование)

Вывод: TEST-4 лучше управляет процессами, меньше блокировок

2. Память (Memory)

TEST-1:

  • memory_swpd: 203-217 (использует swap)
  • memory_free: 179-182 (низкая свободная память)
  • memory_buff: 10-124 (нестабильные буферы)

TEST-4:

  • memory_swpd: 204-237 (стабильное использование)
  • memory_free: 178-329 (больше свободной памяти)
  • memory_buff: 3-124 (стабильные буферы)

Вывод: TEST-4 эффективнее использует память, меньше обращается к swap

3. Ввод-вывод (IO)

TEST-1:

  • io_bi: 66,077-86,873 (очень высокая активность чтения)
  • io_bo: 3,474-7,329 (высокая активность записи)

TEST-4:

  • io_bi: 12,455-34,691 (в 2-3 раза меньше чтения)
  • io_bo: 3,569-22,387 (сопоставимая запись)

Вывод: TEST-4 значительно снижает нагрузку на IO

4. Системные события

TEST-1:

  • system_in: 10,097-14,285 (высокие прерывания)
  • system_cs: 9,511-13,765 (частые переключения контекста)

TEST-4:

  • system_in: 6,324-9,509 (меньше прерываний)
  • system_cs: 1,505-2,586 (значительно меньше переключений)

Вывод: TEST-4 создает меньше системной нагрузки

5. Использование CPU

TEST-1:

  • cpu_us: 35-57% (умеренная пользовательская нагрузка)
  • cpu_sy: 4-5% (низкая системная нагрузка)
  • cpu_id: 17-47% (простой уменьшается со временем)
  • cpu_wa: 10-17% (высокое ожидание IO)

TEST-4:

  • cpu_us: 59-95% (высокая пользовательская нагрузка)
  • cpu_sy: 2-4% (минимальная системная нагрузка)
  • cpu_id: 0-36% (эффективное использование CPU)
  • cpu_wa: 0-3% (минимальное ожидание IO)

Вывод: TEST-4 эффективнее использует CPU, меньше времени тратит на ожидание

Ключевые выводы

Эффективность TEST-4:

  1. На 70-80% меньше переключений контекста
  2. В 2-3 раза меньше операций чтения с диска
  3. В 3-5 раз меньше времени ожидания IO
  4. Более стабильное использование памяти
  5. Выше утилизация CPU для полезной работы

Проблемы TEST-1:

  1. Высокое ожидание IO указывает на проблемы с производительностью диска
  2. Частые переключения контекста свидетельствуют о неэффективном планировании
  3. Нестабильное использование памяти приводит к использованию swap
  4. Заблокированные процессы указывают на contention за ресурсы

Итоговый вердикт

TEST-4 "ARRAY" демонстрирует значительно лучшую эффективность использования системных ресурсов:

  • Оптимизированное использование CPU - больше времени на полезную работу
  • Сниженная нагрузка на IO - меньше операций чтения/записи
  • Стабильное управление памятью - минимальное использование swap
  • Эффективное планирование процессов - меньше блокировок и переключений

Производительность TEST-4 подтверждается на всех уровнях: от дисковой подсистемы до управления процессами, что объясняет его более быстрое выполнение по сравнению с TEST-1 "JOIN".

Общий итог : Часть-2 "TUNING"

Для условий высокой параллельной нагрузки и конкуренции за вычислительные ресурсы, с точки зрения производительности СУБД - использование частичной агрегации оказывает кардинальное влияние на увеличение производительности СУБД .

Производительность СУБД:

Среднее увеличение операционной скорости при использовании запроса "ARRAY" составило 120.15%

❓Сформируй общий итог о сравнении производительности и показателей инфраструктуры в ходе нагрузочного тестирования.

Сводка результатов нагрузочного тестирования

🚀 Производительность СУБД

  • TEST-4 "ARRAY" превосходит TEST-1 "JOIN" на 120.15% по операционной скорости
  • Время выполнения сокращено с 59.15 до 33.27 секунд (ускорение в 1.8 раза)
  • Архитектурное превосходство подхода с агрегацией данных подтверждено на всех уровнях

📊 Анализ эффективности выполнения запросов

Планы выполнения:

  • TEST-4 использует современные возможности PostgreSQL: параллельные вычисления, кэширование Memoize, агрегацию через ARRAY_AGG
  • TEST-1 применяет традиционные JOIN с последовательной обработкой
  • Несмотря на более сложный план, TEST-4 демонстрирует лучшую производительность

Ожидания СУБД (Wait Events):

  • TEST-4 снижает нагрузку на IO в 2-3 раза
  • Межпроцессное взаимодействие уменьшено на порядок (с 24K до 131)
  • Меньше блокировок и таймаутов - более стабильная работа

💾 Использование системных ресурсов

Дисковая подсистема:

  • Оба подхода эффективно используют кэширование в памяти
  • Физический IO не является ограничивающим фактором
  • Данные полностью помещаются в оперативной памяти

Процессор и память:

  • TEST-4 эффективнее использует CPU (95% пользовательского времени против 57%)
  • Снижено время ожидания IO с 17% до 3%
  • Более стабильное управление памятью - меньше использования swap

Системные процессы:

  • На 70-80% меньше переключений контекста в TEST-4
  • Минимальное количество заблокированных процессов
  • Снижена системная нагрузка на прерывания и обработку

🎯 Ключевые факторы успеха TEST-4

  1. Частичная агрегация данных - уменьшение объема обрабатываемой информации
  2. Параллельная обработка - эффективное использование многоядерных систем
  3. Оптимизированное кэширование - снижение нагрузки на подсистемы
  4. Уменьшение contention - меньшая конкуренция за ресурсы

📈 Рекомендации для production-среды

  1. Использовать подход с агрегацией для сложных аналитических запросов
  2. Настроить параметры памяти PostgreSQL для оптимального кэширования
  3. Обеспечить достаточный объем RAM для работы с данными в памяти
  4. Использовать параллельные вычисления для тяжелых запросов

💡 Заключение

TEST-4 "ARRAY" демонстрирует кардинальное превосходство над традиционным JOIN-подходом в условиях высокой параллельной нагрузки. Оптимизированное использование вычислительных ресурсов, снижение contention и эффективная работа с памятью делают этот подход предпочтительным для современных высоконагруженных систем.

Итоговый вердикт: Для достижения максимальной производительности в production-среде рекомендуется применять подход с частичной агрегацией данных и использованием массивов, особенно для сложных аналитических запросов в PostgreSQL.

Продолжение цикла "Сравнительный анализ методов оптимизации ресурсоёмкого SQL-запроса под конкурентной нагрузкой с использованием pg_expecto":

4️⃣Часть-4: Использование временных таблиц

5️⃣Часть-5: Оптимизация с помощью WHERE

6️⃣Итог: Сводный анализ