Управление spill-файлами
Spill-файлы (или work-файлы) — это временные файлы, которые Greengage DB создает на диске, когда запросам требуется больше памяти, чем им выделено для выполнения. Они хранят промежуточные результаты соединений, сортировок, группировок и других операций, выходящих за пределы доступной памяти.
Spill-файлы помогают избежать ошибок out-of-memory (OOM) при выполнении SQL-запросов. Вместо того чтобы прервать выполнение запроса при нехватке памяти, Greengage DB переносит избыточные временные данные на диск и продолжает выполнение. Это повышает стабильность системы, особенно при одновременном исполнении большого количества запросов или при обработке большого объема данных одним запросом.
Однако использование spill-файлов может негативно повлиять на производительность кластера, так как операции чтения и записи на диск медленнее, чем работа с памятью. Кроме того, spill-файлы временно занимают дисковое пространство, особенно при выполнении запросов с соединениями больших таблиц, сортировкой или агрегацией больших объемов данных.
Spill-файлы являются временными. Greengage DB автоматически удаляет их после завершения запроса или транзакции. Обычно администраторам не требуется управлять этими файлами вручную. При этом важно понимать, когда и почему создаются spill-файлы — это полезно для настройки запросов, оптимизации конфигурации и контроля за использованием ресурсов.
Когда появляются spill-файлы
Spill-файлы создаются, когда запросу требуется больше памяти, чем ему выделено. Обычно это происходит при ресурсоемких операциях, обрабатывающих большие объемы данных или использующих алгоритмы с высокой нагрузкой на память.
Типичные причины появления spill-файлов:
-
Недостаточное выделение памяти в конфигурации кластера. Объем памяти, доступный запросу, задается параметрами конфигурации, такими как
statement_mem
,max_statement_mem
иwork_mem
. Убедитесь, что их значения соответствуют предполагаемой нагрузке и ресурсам кластера. -
Перекос данных в кластере. Если данные распределены неравномерно, некоторые сегменты могут хранить значительно больше данных, чем другие. Это может привести к нехватке памяти на отдельных сегментах, даже если общая нагрузка сбалансирована.
-
Неоптимальные запросы, например:
-
Соединения больших таблиц, особенно хеш-соединения, которые используют хеш-таблицы в памяти. Если объем данных превышает лимит памяти, части хеш-таблицы или входных данных записываются на диск.
-
Агрегации без фильтров (выражения
WHERE
), в которых обрабатывается весь набор данных без предварительной выборки. -
Выражение
DISTINCT
на большом числе полей. Такие запросы генерируют все уникальные комбинации значений указанных столбцов, что требует дополнительного места для хранения. -
Выражение
ORDER BY
на больших выборках. Когда используетсяORDER BY
, Greengage DB нужно место для хранения результата сортировки. Сначала они размещаются в памяти, но при недостатке памяти записываются на диск.
-
-
Устаревшая статистика. Если статистика таблиц отсутствует или неактуальна, оптимизатор может неверно оценить объем данных, что приведет к созданию spill-файлов.
Понимание этих причин помогает администраторам и разработчикам оптимизировать запросы и конфигурацию системы, чтобы избежать использования spill-файлов.
Настройка использования spill-файлов
Greengage DB позволяет настраивать следующие параметры работы со spill-файлами:
-
расположение
-
лимиты
-
сжатие
Расположение
Расположение spill-файлов Greengage DB определяется назначенными табличными пространствами. Spill-файлы создаются в каталоге pgsql_tmp/ в указанном табличном пространстве. Например, при использовании табличного пространства по умолчанию путь к spill-файлам имеет вид $MASTER_DATA_DIRECTORY/base/pgsql_tmp/ .
Чтобы поменять расположение spill-файлов, используйте следующие параметры конфигурации:
-
temp_tablespaces
— задает общие табличные пространства для всех временных объектов в базе данных, включая spill-файлы. -
temp_spill_files_tablespaces
— указывает отдельные табличные пространства специально для spill-файлов. Если этот параметр задан, он имеет приоритет надtemp_tablespaces
для размещения spill-файлов.
Чтобы настроить отдельное табличное пространство для spill-файлов, создайте его и выполните следующие команды:
$ gpconfig -c temp_spill_files_tablespaces -v '<spill_tablespace>' --masteronly
$ gpstop -u
где <spill_tablespace>
— имя отдельного табличного пространства.
Вы также можете указать несколько табличных пространств через запятую:
$ gpconfig -c temp_spill_files_tablespaces -v '<spill_tablespace1>,...,<spill_tablespaceN>' --masteronly
$ gpstop -u
Подробности смотрите в разделе Настройка табличных пространств по умолчанию.
Лимиты
Максимальное количество одновременно существующих spill-файлов задается параметром gp_workfile_limit_files_per_query
.
Он определяет, сколько spill-файлов может создать один запрос на каждом сегменте.
Значение по умолчанию — 100000
— достаточно для большинства случаев.
Если этого лимита недостаточно для выполнения запросов, рекомендуется оптимизировать их, чтобы уменьшить использование spill-файлов.
Значение 0
отключает лимит.
Для управления объемом дискового пространства, используемого под spill-файлы, доступны следующие параметры:
-
gp_workfile_limit_per_query
— максимальный объем (в килобайтах), который один запрос может использовать на каждом сегменте. -
gp_workfile_limit_per_segment
— общий объем, доступный для spill-файлов всех выполняемых запросов на каждом сегменте.
По умолчанию оба параметра равны 0
, что означает отсутствие ограничений.
Чтобы задать лимиты на использование диска spill-файлами, выполните команды следующего вида:
$ gpconfig -c gp_workfile_limit_per_query -v '2097152'
$ gpconfig -c gp_workfile_limit_per_segment -v '16777216'
$ gpstop -r
Обратите внимание, что gp_workfile_limit_per_segment
задается на сегментах и требует перезапуска кластера.
Параметр gp_workfile_limit_per_query
можно изменить с помощью перезагрузки конфигурации.
Порог создания spill-файлов
При использовании ресурсных групп для управления ресурсами кластера можно настроить порог использования памяти (в процентах). Когда транзакция потребляет этот процент доступной памяти группы, создаются spill-файлы.
Порог использования памяти можно задать на двух уровнях:
-
Ресурсная группа — атрибут ресурсной группы
MEMORY_SPILL_RATIO
задает порог по умолчанию для всех транзакций в этой группе. -
Сессия — параметр конфигурации
memory_spill_ratio
позволяет переопределить значение по умолчанию для конкретной сессии или транзакции.
Подробнее о пороге создания spill-файлов см. в разделе Создание spill-файлов: MEMORY_SPILL_RATIO.
Сжатие
Чтобы уменьшить размер spill-файлов, можно включить их сжатие с помощью параметра gp_workfile_compression
типа boolean
:
$ gpconfig -c gp_workfile_compression -v ON --masteronly
$ gpstop -u
При использовании сжатия учитывайте, что оно снижает нагрузку на диск и объем хранения за счет увеличения нагрузки на CPU.
Сжатие применяется к spill-файлам, которые порождаются операциями хеш-агрегирования (hash aggregate) и хеш-соединения (hash join). Остальные spill-файлы не сжимаются.
Сжатие использует дополнительную память, которая не учитывается в лимите statement_mem
.
Объем этой памяти ограничен параметром gp_workfile_compression_overhead_limit
, который по умолчанию равен 2GB
.
Если одновременно выполняется много запросов со сжатием spill-файлов и достигается этот лимит, Greengage DB перестает сжимать новые spill-файлы.
Чтобы изменить лимит дополнительной памяти для сжатия, задайте новое значение gp_workfile_compression_overhead_limit
или установите его в 0
, чтобы отключить ограничение.
Проверка spill-файлов
Spill-файлы являются временными — они существуют только во время выполнения запроса. Чтобы определить, создает ли запрос spill-файлы, необходимо просматривать соответствующие представления системного каталога во время выполнения запроса. После завершения запроса файлы и связанные с ними статистики автоматически удаляются.
Существует два способа проверить использование spill-файлов:
-
Отслеживать представления системного каталога
gp_workfile_*
во время выполнения запроса. Эти представления отображают информацию об активных spill-файлах в момент просмотра. -
Использовать SQL-команду
EXPLAIN ANALYZE
. Ее вывод содержит сведения о spill-файлах, созданных при выполнении запроса. Это позволяет оценить объем данных, сброшенных на диск, и выявить возможные проблемы в плане выполнения запроса.
Чтобы воспроизвести примеры из этого раздела, выполните следующие шаги:
-
Подключитесь к мастер-хосту Greengage DB с помощью
psql
, как описано в статье Подключение к Greengage DB с использованием psql. -
Создайте новую базу данных и подключитесь к ней:
CREATE DATABASE marketplace; \c marketplace
-
Создайте тестовую таблицу:
CREATE TABLE items ( item_id SERIAL PRIMARY KEY, category TEXT, price NUMERIC, count NUMERIC, value NUMERIC, description TEXT ) DISTRIBUTED BY (item_id);
-
Заполните таблицу большим объемом данных, например, одним миллионом строк:
INSERT INTO items (category, price, count, value, description) SELECT CASE WHEN id % 5 = 0 THEN 'Category A' WHEN id % 5 = 1 THEN 'Category B' WHEN id % 5 = 2 THEN 'Category C' WHEN id % 5 = 3 THEN 'Category D' ELSE 'Category E' END, RANDOM() * 1000, RANDOM() * 1000, RANDOM() * 1000, md5(RANDOM()::text) FROM generate_series(1, 1000000) id;
-
Установите низкий лимит памяти для выполнения запроса, который будет исчерпан при выполнении ресурсоемкого запроса, например,
5MB
. При достижении этого лимита будут создаваться spill-файлы:SET statement_mem = '5MB';
В такой конфигурации следующий SQL-запрос использует всю доступную память и начнет создавать spill-файлы:
SELECT DISTINCT (item_id, price, count), value
FROM items
GROUP BY item_id
ORDER BY value;
Чтобы проверить spill-файлы, создаваемые этим запросом, откройте другое подключение psql
к той же базе данных и выполните запросы к системным представлениям, перечисленным ниже во время выполнения запроса.
После завершения запроса spill-файлы удаляются, и представления не содержат данных.
Не запускайте приведенные примеры в production-средах. Они меняют конфигурацию и могут создавать высокую нагрузку, что потенциально приведет к сбоям. Используйте для тестирования только тестовые стенды или стенды разработки.
Представления gp_toolkit.gp_workfile_*
Следующие представления административной схемы gp_toolkit
содержат информацию об активных spill-файлах.
Они полезны для мониторинга и оптимизации использования ресурсов:
-
gp_toolkit.gp_workfile_usage_per_query
— показывает использование spill-файлов по запросам. Содержит агрегированную информацию о количестве и размере spill-файлов, созданных каждым запросом. Представление содержит такие метаданные, как размер файлов, их количество, соответствующий SQL-запрос и другую информацию. Это позволяет определить запросы с высоким потреблением ресурсов.Пример:
SELECT datname, usename, query, segid, size, numfiles FROM gp_toolkit.gp_workfile_usage_per_query;
Пример вывода:
datname | usename | query | segid | size | numfiles -------------+---------+--------------------------------------------------------------------------------------------+-------+----------+---------- marketplace | gpadmin | SELECT DISTINCT (item_id, price, count), value FROM items GROUP BY item_id ORDER BY value; | 0 | 18317312 | 1 marketplace | gpadmin | SELECT DISTINCT (item_id, price, count), value FROM items GROUP BY item_id ORDER BY value; | 3 | 18317312 | 1 marketplace | gpadmin | SELECT DISTINCT (item_id, price, count), value FROM items GROUP BY item_id ORDER BY value; | 1 | 18219008 | 1 marketplace | gpadmin | SELECT DISTINCT (item_id, price, count), value FROM items GROUP BY item_id ORDER BY value; | 2 | 18350080 | 1 (4 rows)
-
gp_toolkit.gp_workfile_entries
— предоставляет подробную информацию об активных spill-файлах в кластере. В отличие от представленияgp_workfile_usage_per_query
, которое агрегирует данные на уровне запроса, вgp_toolkit.gp_workfile_entries
каждая строка соответствует одному оператору (столбецoptype
), создавшему spill-файл. Такой уровень детализации помогает при глубоком анализе запросов и их настройке.Пример:
SELECT datname, usename, query, segid, optype, size, numfiles FROM gp_toolkit.gp_workfile_entries;
Пример вывода:
datname | usename | query | segid | optype | size | numfiles -------------+---------+--------------------------------------------------------------------------------------------+-------+--------+----------+---------- marketplace | gpadmin | SELECT DISTINCT (item_id, price, count), value FROM items GROUP BY item_id ORDER BY value; | 2 | Sort | 18382848 | 1 marketplace | gpadmin | SELECT DISTINCT (item_id, price, count), value FROM items GROUP BY item_id ORDER BY value; | 3 | Sort | 18284544 | 1 marketplace | gpadmin | SELECT DISTINCT (item_id, price, count), value FROM items GROUP BY item_id ORDER BY value; | 0 | Sort | 18350080 | 1 marketplace | gpadmin | SELECT DISTINCT (item_id, price, count), value FROM items GROUP BY item_id ORDER BY value; | 1 | Sort | 18284544 | 1 (4 rows)
-
gp_toolkit.gp_workfile_usage_per_segment
— отображает использование spill-файлов на уровне сегментов. Позволяет оценить, как spill-файлы распределяются по кластеру. Это представление помогает выявить дисбаланс нагрузки и возможные узкие места в производительности.Пример:
SELECT * FROM gp_toolkit.gp_workfile_usage_per_segment;
Пример вывода:
segid | size | numfiles -------+----------+---------- 1 | 18251776 | 1 0 | 18350080 | 1 2 | 18350080 | 1 3 | 18284544 | 1 -1 | 0 | (5 rows)
Представления gp_toolkit.gp_workfile_entries
, gp_toolkit.gp_workfile_usage_per_query
и gp_toolkit.gp_workfile_usage_per_segment
доступны всем пользователям.
Однако для обычных пользователей (не суперпользователей) отображаются только данные по базам, к которым у них есть доступ.
Команда EXPLAIN ANALYZE
В тестовых средах вы можете проверить, создает ли запрос spill-файлы, с помощью команды EXPLAIN ANALYZE
.
Эта команда строит план запроса и выполняет его, а затем выводит подробную статистику выполнения, включая информацию об использовании памяти и наличии spill-файлов.
Например, следующая команда выводит план запроса и сведения о spill-файлах:
EXPLAIN ANALYZE
SELECT DISTINCT (item_id, price, count), value
FROM items
GROUP BY item_id
ORDER BY value;
Результат:
QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------- ------- Unique (cost=2665.04..2875.04 rows=16800 width=68) (actual time=1630.148..4123.738 rows=1000000 loops=1) Group Key: value, (ROW(item_id, price, count)) -> Gather Motion 4:1 (slice2; segments: 4) (cost=2665.04..2791.04 rows=16800 width=68) (actual time=1630.147..3624.408 rows=1000000 loops=1) Merge Key: value, (ROW(item_id, price, count)) -> Unique (cost=2665.04..2791.04 rows=4200 width=68) (actual time=1613.354..1982.876 rows=250461 loops=1) Group Key: value, (ROW(item_id, price, count)) -> Sort (cost=2665.04..2707.04 rows=4200 width=68) (actual time=1613.352..1884.099 rows=250461 loops=1) Sort Key (Distinct): value, (ROW(item_id, price, count)) Sort Method: external merge Disk: 71488kB -> Redistribute Motion 4:4 (slice1; segments: 4) (cost=478.00..1486.00 rows=4200 width=68) (actual time=287.676..560.936 rows=250461 lo ops=1) Hash Key: value -> HashAggregate (cost=478.00..814.00 rows=4200 width=68) (actual time=286.894..509.883 rows=250659 loops=1) Group Key: item_id Extra Text: (seg1) 249548 groups total in 32 batches; 1 overflows; 249548 spill groups. (seg1) Hash chain length 3.9 avg, 14 max, using 72165 of 73728 buckets; total 1 expansions. -> Seq Scan on items (cost=0.00..436.00 rows=4200 width=100) (actual time=0.012..130.936 rows=250659 loops=1) Planning time: 0.139 ms (slice0) Executor memory: 884863K bytes. * (slice1) Executor memory: 3671K bytes avg x 4 workers, 3671K bytes max (seg0). Work_mem: 2511K bytes max, 19201K bytes wanted. * (slice2) Executor memory: 4753K bytes avg x 4 workers, 4753K bytes max (seg0). Work_mem: 4698K bytes max, 73909K bytes wanted. Memory used: 5120kB Memory wanted: 148316kB Optimizer: Postgres query optimizer Execution time: 4246.067 ms (25 rows)
Если во время выполнения запроса создавались spill-файлы, это отображается в строках со звездочкой ( * (slice1)
и * (slice2)
) после плана запроса.
Параметры Memory used
и Memory wanted
показывают, сколько памяти фактически использовал запрос и сколько ему требовалось.
Обычно при создании spill-файлов значение Memory wanted
превышает Memory used
, которое, в свою очередь, зависит от statement_mem
(лимита памяти на запрос) и memory_spill_ratio
(порога использования памяти).
Минимизация использования spill-файлов
Хотя spill-файлы позволяют выполнять запросы при нехватке памяти, они могут существенно снижать производительность и занимать дисковое пространство. Поэтому по возможности рекомендуется сводить к минимуму их использование.
Всегда старайтесь уменьшить число spill-файлов, изменяя запросы, распределение данных или настройки памяти. Следуйте этим рекомендациям, чтобы снизить или полностью избежать создания spill-файлов:
-
Поддерживайте статистику в актуальном состоянии. Регулярно обновляйте статистику таблиц и индексов. Актуальная статистика помогает планировщику запросов выбирать более эффективные планы выполнения. Узнайте больше в статье Сбор статистики с помощью ANALYZE.
-
Оптимизируйте SQL-запросы. Проверьте и при необходимости упростите логику запросов для повышения производительности:
-
Используйте фильтры. Применяйте условия фильтрации как можно раньше, чтобы сократить объем обрабатываемых в дальнейшем данных.
-
Используйте правильный порядок таблиц в соединениях. При выполнении
LEFT JOIN
Greengage DB строит хеш-таблицу на основе таблицы справа в выражении. Если справа указана большая таблица, это может привести к нехватке памяти. По возможности размещайте большие таблицы в левой части выраженияLEFT JOIN
. Также ограничивайте число возвращаемых полей, чтобы сократить объем обрабатываемых данных. -
Избегайте
ORDER BY
. В общем случае использованиеORDER BY
в СУБД Greengage не рекомендуется. Если сортировка необходима, старайтесь уменьшить объем данных или выполняйте сортировку на стороне клиента после возвращения результата запроса. -
Минимизируйте число полей в
DISTINCT
. Сократите число полей, указанных вDISTINCT
, чтобы снизить нагрузку. Каждое дополнительное поле резко увеличивает число уникальных комбинаций, что может привести к исчерпанию памяти.
-
-
Обеспечьте равномерное распределение данных. Убедитесь, что данные равномерно распределены по сегментам кластера. Это гарантирует, что все сегменты обрабатывают сопоставимые объемы данных и не перегружаются. Узнайте больше в статье Распределение данных.
-
Выделяйте достаточно ресурсов. Если предполагаемая рабочая нагрузка включает запросы, создающие spill-файлы и не поддающиеся оптимизации, выделите больше ресурсов для их эффективного выполнения:
-
Увеличьте лимиты памяти, заданные параметрами конфигурации
statement_mem
иmax_statement_mem
. -
Настройте доступные ресурсы с помощью ресурсных групп или ресурсных очередей для более эффективного управления памятью и CPU.
-
Чтобы избежать сбоев из-за чрезмерного количества или объема spill-файлов, настройте параметры, ограничивающие их использование: gp_workfile_limit_files_per_query
, gp_workfile_limit_per_query
и gp_workfile_limit_per_segment
.