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 индексов (независимо от типа столбца или индекса).
Индексы 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 для этого столбца может ускорить сортировку.Подробные принципы выбора см. в разделе Ключи сортировки и локальность данных.
lz4. Другие типы см. в разделе Использование сжатия.О влиянии на производительность см. раздел Сжатие и производительность.
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, что указывает на использование единого сегмента (т.е. сегментирование не выполняется).
Дополнительные технические сведения см. в разделе Технический обзор 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при создании таблицы было удалено.
Примечание!
Это параметры конфигурации уровня таблицы. Они должны быть установлены с использованием клаузулыWITH(mars3options='a=1,b=2,...')при создании таблицы. Они применяются к отдельным таблицам и не могут быть изменены после создания. Дополнительную информацию см. в разделе Параметры таблиц базы данных.
Параметры для контроля размера Run L0 (косвенно влияют на более высокие уровни):
| Параметр | Единица | По умолчанию | Диапазон | Описание |
|---|---|---|---|---|
rowstore_size |
МБ | 64 | 8 – 1024 | Контролирует момент переключения Run L0. Новый Run запускается, когда размер данных превышает это значение. |
Параметры порога сжатия (регулируют коэффициент сжатия и эффективность чтения):
| Параметр | Единица | По умолчанию | Диапазон | Описание |
|---|---|---|---|---|
compress_threshold |
Кортежи | 1200 | 1 – 100000 | Порог сжатия. Контролирует максимальное количество кортежей, сжимаемых вместе в одной единице на столбец. |
Параметры режима загрузки данных:
| Параметр | Единица | По умолчанию | Диапазон | Описание |
|---|---|---|---|---|
prefer_load_mode |
- | normal | normal / bulk / single | Режим загрузки данных.normal: Сначала запись в Rowstore L0, затем сброс в Columnstore L1 после достижения rowstore_size. Асинхронная конвертация; подходит для высокочастотной записи небольшими пакетами при достаточном вводе-выводе.bulk: Прямая запись в Columnstore L1. Синхронная конвертация; подходит для низкочастотной записи большими пакетами при ограниченном вводе-выводе.single: Прямая вставка в rowstore (Shared Buffers). |
Параметры усиления размера уровня:
| Параметр | Единица | По умолчанию | Диапазон | Описание |
|---|---|---|---|---|
level_size_amplifier |
- | 8 | 1 – 1000 | Коэффициент усиления для размеров уровней. Порог для уплотнения рассчитывается как: rowstore_size * (level_size_amplifier ^ level). Более высокие значения замедляют чтение, но ускоряют запись. Настраивайте в зависимости от рабочей нагрузки (преобладание записи или чтения) и коэффициентов сжатия. Убедитесь, что количество Run на уровень не станет чрезмерным, так как это влияет на производительность запросов и может заблокировать новые вставки. |
Следующий параметр определяет количество сегментов (buckets):
| Параметр | Единица | Значение по умолчанию | Диапазон | Описание |
|---|---|---|---|---|
nbuckets |
— | 1 | 1 – 128 | Количество сегментов. Управляет числом сегментов для оптимизации производительности запросов. Рекомендации по использованию см. в разделе Лучшие практики использования MARS3 Bucket в рамках раздела «Лучшие практики проектирования таблиц и распределения данных». |
Пример конфигурации:
CREATE EXTENSION matrixts;
CREATE TABLE t(
time timestamp with time zone,
tag_id int,
i4 int4,
i8 int8
)
USING MARS3
WITH (compresstype=zstd, compresslevel=3, compress_threshold=1200,
mars3options='rowstore_size=64,prefer_load_mode=normal,level_size_amplifier=8, 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 движков хранения см. в разделе Лучшие практики проектирования таблиц и распределения данных.