MARS3 — это проприетарный движок хранения на основе LSM-дерева, разработанный компанией YMatrix. Он использует архитектуру гибридного строчно-колоночного хранения. В дополнение к традиционной модели LSM, MARS3 внедряет двухэтапный путь записи «сначала строки, затем столбцы». Такой подход наследует преимущества строкового хранения для операций записи и сохраняет высокопроизводительные аналитические возможности колоночного хранения.
Ключевые особенности:
MARS3 разработан для удовлетворения требований как аналитической обработки (AP), так и транзакционной обработки (TP).
Движок поддерживает операции обновления и удаления через cláusулы UPDATE (за исключением режима Unique) и DELETE. Также поддерживаются добавление и удаление столбцов, операции COPY и pg_dump.
Каждая таблица MARS3 внутри использует структуру LSM-дерева (Log-Structured Merge-Tree). LSM-дерево — это многоуровневая, упорядоченная дисковая структура данных. Её основная философия заключается в использовании производительности диска для пакетной последовательной записи, что значительно превосходит случайную запись.
_1688719823.png)
Данные в MARS3 хранятся в упорядоченном виде. Непрерывный сегмент упорядоченных данных называется Run.
Существует два типа Run:
Каждый Run имеет ограничение по размеру:
max_runsize указывает максимальный размер одного Run при создании таблицы. Максимальное значение составляет 16384 МБ.4096 МБ.matrixts_internal.mars3_files.SELECT * FROM matrixts_internal.mars3_files('test');
Основные типы файлов:
MARS3 организует данные по модели LSM-дерева. Файлы Run организованы в Уровни (Levels), от L0 до L9 (максимум 10 уровней).
Уплотнение (compaction) запускается, когда:
Во время уплотнения несколько Run объединяются в один Run и переносятся на следующий более высокий уровень. Для ускорения продвижения допускаются несколько параллельных задач слияния в пределах одного уровня.

Фоновые процессы слияния в YMatrix периодически обнаруживают состояние таблиц и выполняют уплотнение. Служебная функция matrixts_internal.mars3_level_stats предоставляет информацию о статусе каждого уровня таблицы MARS3:
SELECT * FROM matrixts_internal.mars3_level_stats('test') LIMIT 10;
Эта операция критически важна для оценки здоровья таблицы, например, для проверки слияния Run в соответствии с ожиданиями, выявления избыточного количества невидимых Run и обеспечения того, чтобы количество Run оставалось в нормальных пределах.
Эмпирические правила здоровья:
Данные Columnstore записываются и читаются напрямую, без буферного слоя, такого как Shared Buffers или сброс страниц.
compress_threshold (по умолчанию 1200) строк образуют Range.compress_threshold значений).Если данные столбца внутри Stripe особенно велики, они разбиваются на фрагменты по 1 МБ. Чтение не обязательно выбирает весь объем compress_threshold за один раз.
RUN
└── Range (Разделение по строкам, по умолчанию 1200 строк на range)
├── Stripe столбца 1 (1200 данных)
├── Stripe столбца 2 (1200 данных)
├── Stripe столбца 3 (1200 данных)
└── ...
MARS3 использует стратегию хранения «Сначала строки, затем столбцы». Данные поступают в систему в формате, оптимизированном для записи (rowstore), и постепенно конвертируются в формат, оптимизированный для анализа (columnstore), посредством фонового управления. Это обеспечивает непрерывную запись и бесперебойный анализ.
Преимущества по сравнению с прямой колоночной записью:
INSERT, затем записываются в Rowstore Run Уровня 0 (L0).prefer_load_mode и rowstore_size (см. Конфигурация):rowstore_size данные сбрасываются в Columnstore Run L1. По сравнению с режимом Bulk, это требует одной дополнительной операции ввода-вывода, а конвертация из строк в столбцы происходит асинхронно. Подходит для высокочастотной записи небольшими пакетами при достаточной мощности ввода-вывода и высокой чувствительности к задержкам.Normal, это сокращает одну операцию ввода-вывода, а конвертация происходит синхронно. Подходит для низкочастотной записи большими пакетами при ограниченной мощности ввода-вывода и низкой чувствительности к задержкам.Shared Buffers.Дополнительные сведения см. в разделе Путь записи.
MARS3 в настоящее время поддерживает индексы BRIN и B-Tree.
Примечание!
Одна таблица MARS3 поддерживает максимум 16 индексов (независимо от типа столбца или индекса). Таблицы MARS3 поддерживают только индексыmars3_brinиmars3_btree.CREATE INDEX CONCURRENTLYсейчас не поддерживается для таблиц MARS3.
Индексы BRIN
mars3_brin и mars3_default_brin. Поддерживаются создание и удаление.CREATE INDEX USING BRIN (который приносит пользу только сканированию по индексу), Default BRIN также улучшает последовательное сканирование (Seq Scan), значительно повышая эффективность запросов. Важно отметить, что Default BRIN не занимает слот индекса. Даже при включенном Default BRIN можно создать до 16 дополнительных индексов.| Функция | mars3_brin | mars3_default_brin |
|---|---|---|
| Создание | Ручное | Автоматическое (ручные действия не требуются) |
| Поддержка запросов | Фильтрация данных только при сканировании по индексу | Фильтрация данных как при сканировании по индексу, так и при последовательном сканировании |
| Версия технологии | brinV2 | brinV2 |
| Параметризованный запрос | Поддерживается (param-IndexScan) | Поддерживается (param-SeqScan) |
Индексы B-Tree
B-Tree — это индекс общего назначения, основанный на сбалансированной многопутевой древовидной структуре. Он организует узлы индекса по значению ключа, обеспечивая быстрое и точное позиционирование отдельных строк или небольших диапазонов. Сложность запроса остается стабильной на уровне O(logN). Он эффективно поддерживает проверки на равенство, диапазонные сканирования и операции сортировки. Благодаря независимости от физического распределения данных, B-Tree обеспечивает исключительную стабильность в сценариях транзакций с высокой конкуренцией. Это выбор по умолчанию для первичных ключей, уникальных ограничений и запросов с высокой селективностью. Однако он не подходит для столбцов с низкой селективностью или широких диапазонных сканирований больших таблиц.
mars3btree — это специализированная реализация B-Tree для MARS3. Внутренние страницы остаются стандартными страницами B-Tree. Поддерживаются два типа:
Ключ сортировки является критически важным элементом проектирования, определяющим эффективность сканирования и долгосрочную стабильность. Упорядоченные данные в сочетании с надежными метаданными на уровне блоков значительно повышают производительность сканирования.
COLLATE C для этого столбца может ускорить сортировку.Подробные принципы выбора см. в разделе Ключи сортировки и локальность данных.
Начиная с версии 6.8.2 MARS3 по умолчанию использует типизированный кодировщик для сжатия данных. Если при создании таблицы не указан compresstype, используется именно этот способ. Также можно явно указать compresstype=auto, чтобы использовать типизированный кодировщик. Он динамически выбирает наиболее подходящий способ кодирования на основе типа столбца и характеристик каждого блока данных, без дополнительного вмешательства.
Параметр automode задает приоритет типизированного кодировщика:
automode=1: приоритет степени сжатия.automode=2: приоритет скорости кодирования и декодирования. Значение по умолчанию: 2.Типизированный кодировщик имеет следующие особенности:
lz4 и zstd.Сейчас типизированный кодировщик поддерживает только следующие типы:
smallint, integer, bigintdate, time, timestamp, timestamptztext, varcharnumeric, только если для столбца задана фиксированная точностьfloatДля остальных типов MARS3 использует zstd уровня 3.
О влиянии на производительность см. раздел Сжатие и производительность.
DELETE. Для обновлений не требуется явная клаузула UPDATE; выполнение INSERT с тем же уникальным ключом автоматически выполняет обновление. Уникальный ключ соответствует ключу сортировки, определенному при создании.CREATE TABLE mars3_t(c1 int NOT NULL, c2 int) USING MARS3 WITH (uniquemode=true) ORDER BY (c1, c2); Здесь уникальный ключ — (c1, c2).Примечание!
Если включен режим Unique, первое поле в клаузулеORDER BYдолжно быть определено с ограничениемNOT NULL.
Технические подробности см. в разделе Обновления и удаления.
Технические подробности см. в разделе Фоновое управление.
Dead (мертвые) данные. Кроме того, можно запланировать выполнение VACUUM для профилактической очистки Dead данных.MARS3 Bucket — это механизм оптимизации параллельного выполнения на уровне хранилища, разработанный YMatrix для сценариев параллельного сканирования в архитектуре MPP. Организуя данные в несколько логических сегментов (buckets) на основе хеша ключа распределения на этапе записи, он гарантирует, что данные с одинаковым ключом распределения будут обрабатываться одним и тем же воркером во время параллельных сканирований. Это сохраняет семантику распределения данных (локус), позволяет избежать ненужного перераспределения данных (Motion) и обеспечивает скачок производительности от «более быстрого сканирования» к «более локальным вычислениям».
create table foo (c1 int, c2 int) using mars3 with (mars3options='nbuckets = 2');
Допустимые значения для nbuckets находятся в диапазоне от 1 до 128. Значение по умолчанию равно 1, что указывает на использование единого сегмента (т.е. сегментирование не выполняется). Включайте Bucket только для больших таблиц, которые выигрывают от параллельного сканирования. Bucket опирается на семантику hash-распределения, поэтому для таблиц без hash-распределения практической пользы нет. Unique Mode и continuous view не поддерживают режим Bucket. Изменение nbuckets является изменением уровня rewrite, поэтому значение лучше выбирать при создании таблицы.
Дополнительные технические сведения см. в разделе Технический обзор MARS3 Bucket.
При установленном расширении matrixts простейший способ создания таблицы — добавить клаузулы USING и ORDER BY в оператор CREATE TABLE. Расширенные примеры см. в разделе Лучшие практики проектирования таблиц.
CREATE TABLE metrics (
ts timestamp,
dev_id bigint,
power float,
speed float,
message text
) USING MARS3
ORDER BY (dev_id, ts);
Примечание!
Таблицы MARS3 поддерживают индексы BRIN, но они не являются обязательными.
Начиная с версии 6.3.0, требование указывать клаузулуORDER BYпри создании таблицы было удалено. Однако в production-среде рекомендуется явно проектировать ключ сортировки на основе основных условий фильтрации. Если включен Unique Mode, корректный ключ сортировки обязателен.
Примечание!
Параметры уровня таблицы MARS3 задаются в двух местах: во внешнемWITH (...)и во внутренней строкеmars3options='a=1,b=2,...'. Эти категории нельзя смешивать. Например,compresstype,compress_threshold,automodeиuniquemodeотносятся к внешним параметрамWITH, аrowstore_size,prefer_load_modeиnbucketsотносятся кmars3options. Дополнительную информацию см. в разделе Параметры таблиц базы данных.
Распространенные внешние параметры WITH:
| Параметр | Единица | По умолчанию | Диапазон | Описание |
|---|---|---|---|---|
compresstype |
— | auto (6.8.2 и выше) |
none / auto / zstd / zlib / lz4 / rle_type / mxcustom |
Метод сжатия на уровне таблицы. auto использует типизированный кодировщик. mxcustom требует параметр encodechain. |
compresslevel |
— | 0 | 0 – 19 | Уровень сжатия. Фактический диапазон зависит от алгоритма; например, для zlib обычно используется 1 – 9. |
compress_threshold |
Кортежи | 1200 | 1 – 65535 | Порог сжатия. Контролирует максимальное число кортежей, сжимаемых вместе для каждого столбца в одном Range. Слишком малое значение снижает эффект сжатия, слишком большое увеличивает потребление памяти. |
encodechain |
— | Пусто | Строка цепочки кодирования | Используется только с compresstype=mxcustom для задания пользовательской цепочки кодирования. |
automode |
— | 2 | 1 / 2 | Стратегия для compresstype=auto. 1 отдает приоритет степени сжатия, 2 отдает приоритет скорости кодирования и декодирования. |
object_size |
МБ | 64 | Положительное целое | Размер объекта. Обычно не требует ручной настройки. |
use_table_encoding |
— | 0 | 0 / 1 | Использовать ли настройки кодирования уровня таблицы с более высоким приоритетом. Обычно оставляют значение по умолчанию. |
uniquemode |
— | false |
true / false |
Включает Unique Mode. При включении ключ сортировки выступает уникальным ключом, а новые записи с тем же ключом заменяют старые версии. |
Распространенные параметры mars3options:
| Параметр | Единица | По умолчанию | Диапазон | Описание |
|---|---|---|---|---|
prefer_load_mode |
— | normal |
normal / bulk / single |
Режим загрузки данных. normal — смешанная стратегия по умолчанию; bulk лучше подходит для редкой пакетной загрузки большого объема; single записывает напрямую в rowstore и подходит для небольших записей с требованием низкой задержки. |
rowstore_size |
МБ | 64 | 8 – 4096 | Контролирует момент переключения L0 RowStore Run. Новый Run запускается, когда размер данных превышает это значение. |
max_runsize |
МБ | 4096 | 64 – 16384 | Максимальный размер одного Run. |
level_size_amplifier |
— | 8 | 1 – 1000 | Коэффициент усиления размера уровня. Большее значение реже запускает compaction, но повышает риск усиления чтения; меньшее значение делает compaction более активным, но увеличивает фоновую нагрузку ввода-вывода. |
default_brinkeys |
— | 30 | -1 – максимальный номер атрибута | Управляет столбцами, покрываемыми Default BRIN. 0 отключает его; -1 позволяет системе включить его для всех поддерживаемых сравнимых столбцов; N включает его для первых N сравнимых столбцов. |
nbuckets |
— | 1 | 1 – 128 | Количество бакетов. Используется для сохранения семантики распределения при параллельном сканировании. Рекомендации см. в разделе MARS3 Bucket Best Practices в документе «Лучшие практики проектирования таблиц и распределения данных». |
Рекомендации по выбору prefer_load_mode:
| Режим | Подходящие сценарии | Примечания |
|---|---|---|
normal |
Режим по умолчанию для высокочастотных небольших пакетов и непрерывной записи. | В конце записи MARS3 по размеру кэша решает, оставить данные в RowStore или сбросить их в ColumnStore, балансируя задержку и эффективность аналитики. |
bulk |
Редкая пакетная загрузка большого объема, когда важнее сжатие ColumnStore и AP-запросы. | Потребляет больше памяти; задержка одной операции записи обычно выше, чем у normal / single. |
single |
Одиночные или небольшие записи с чувствительностью к задержке. | Данные сначала попадают в RowStore, поэтому сжатие, BRIN и эффективность AP-запросов обычно ниже, чем у ColumnStore. После больших загрузок отслеживайте фоновый compaction или выполняйте VACUUM при необходимости. |
Пример конфигурации:
CREATE EXTENSION matrixts;
CREATE TABLE t(
time timestamp with time zone,
tag_id int,
i4 int4,
i8 int8
)
USING MARS3
WITH (compresstype=auto, automode=2, compress_threshold=1200,
mars3options='rowstore_size=64,prefer_load_mode=normal,level_size_amplifier=8,default_brinkeys=30,nbuckets=2')
DISTRIBUTED BY (tag_id)
PARTITION BY RANGE (time)
(
START ('2026-02-01 00:00:00+08')
END ('2026-03-01 00:00:00+08')
EVERY (INTERVAL '1 day')
)
ORDER BY (time, tag_id);
matrixts_internal.mars3_level_stats: Проверяет статус каждого уровня в таблице MARS3. Полезно для оценки здоровья (например, прогресс слияния, количество Run).matrixts_internal.mars3_files: Проверяет статус файлов таблицы MARS3 (файлы данных, Delta, индексы и т.д.).matrixts_internal.mars3_info_brin: Проверяет статус конкретного индекса BRIN на таблице MARS3.HEAP — это движок хранения по умолчанию в YMatrix, унаследованный от PostgreSQL. Также известный как кучное хранение (heap storage), он поддерживает только строковое хранение и не поддерживает колоночное хранение или сжатие. Он основан на механизме MVCC и подходит для сценариев с частыми обновлениями и удалениями.
В рамках MVCC таблицы HEAP не удаляют данные физически во время операций обновления или удаления. Вместо этого они полагаются на информацию о версиях для скрытия старых данных (управление видимостью). Следовательно, обширные обновления или удаления приводят к непрерывному росту физического пространства, занимаемого таблицей HEAP. Требуется регулярное выполнение VACUUM для освобождения места от старых данных.
Вы можете создать таблицу HEAP в YMatrix, используя следующий SQL:
CREATE TABLE disk_heap(
time timestamp with time zone,
tag_id int,
read float,
write float
)
DISTRIBUTED BY (tag_id);
AORO (Append-Only Row-Oriented) — это парадигма организации хранения, разработанная для аналитических баз данных. Данные записываются непрерывно в режиме «только добавление» (append-only) по строкам. Он не поддерживает обновления или удаления на месте. Версионирование поддерживается через временные метки или идентификаторы транзакций, балансируя пропускную способность записи, эффективность запросов и согласованность MVCC. AORO поддерживает строковое хранение.
Для AO-таблиц с частыми обновлениями и удалениями необходима регулярная очистка старых данных. Однако инструмент VACUUM для AO-таблиц должен сбрасывать битовые карты и сжимать физические файлы, что делает процесс обычно более медленным по сравнению с таблицами HEAP.
Примечание!
Подробную информацию, использование и лучшие практики regarding движков хранения см. в разделе Лучшие практики проектирования таблиц и распределения данных.