Модель данных: catalog, schema, table
Trino подключается к десяткам совершенно разных источников данных одновременно: к PostgreSQL, к Parquet-файлам на S3, к Kafka-топику, к коллекции MongoDB. У каждого из этих источников своя модель именования, свой диалект, свои правила. Чтобы один SQL-движок мог обращаться к ним всем единообразно, нужна общая система координат. В Trino эта система — трёхуровневое имя catalog.schema.table.
Этот урок разбирает каждый уровень: что он означает, на что мапится в реальном источнике, и почему именно такая иерархия позволяет Trino быть «универсальным переводчиком» между ANSI SQL и любым хранилищем.
Trino не хранит данные — он их адресует
Первое, что нужно зафиксировать: Trino — это распределённый SQL query engine, а не база данных. У него нет своего хранилища, нет своих файлов с таблицами, нет индексов в традиционном смысле. Когда вы пишете SELECT * FROM postgresql.public.orders, Trino не достаёт данные из себя — он идёт в реальный PostgreSQL, читает оттуда и возвращает вам результат.
Раз данные живут снаружи, Trino нужен способ однозначно указать: «возьми вот эту таблицу вот из этого источника». Именно для этого и существует трёхуровневое имя. Каждый его компонент отвечает на свой вопрос.
Полное имя postgresql.public.orders читается справа налево как ответ на три вопроса: какая таблица (orders), в какой группе таблиц (public), в каком источнике (postgresql). Это полностью аналогично тому, как файл адресуется путём /диск/папка/файл, только вместо диска — источник данных.
Catalog: подключение к источнику
Catalog в Trino — это набор свойств конфигурации, который определяет доступ к конкретному источнику данных. Catalog отвечает на два вопроса: какой коннектор использовать и с какими параметрами (адрес сервера, учётные данные, настройки).
Ключевая мысль, которая часто ускользает от новичков: catalog — это не «база данных». Catalog — это именованная конфигурация подключения. Один и тот же тип источника может быть подключён несколько раз под разными именами. Например, у вас может быть catalog prod_postgres и catalog staging_postgres — оба используют коннектор postgresql, но указывают на разные серверы.
Catalog описывается файлом etc/catalog/<имя>.properties на сервере Trino. Имя файла становится именем catalog. Минимальное содержимое — строка connector.name:
# Файл etc/catalog/postgresql.properties
connector.name=postgresql
connection-url=jdbc:postgresql://db.example.com:5432/analytics
connection-user=trino_reader
connection-password=secret
Этот файл создаёт catalog с именем postgresql. Чтобы создать второй PostgreSQL-catalog, достаточно положить рядом ещё один файл, например etc/catalog/warehouse_pg.properties, с тем же connector.name=postgresql, но другим connection-url.
Список доступных catalog можно увидеть прямо из SQL:
SHOW CATALOGS;
Catalog
-------------
postgresql
iceberg
tpch
system
(4 rows)
Catalog system присутствует всегда — это встроенный системный catalog Trino. Через него доступны метаданные кластера: список запущенных запросов, нод, каталогов. Его не нужно конфигурировать.
Schema: группа таблиц
Schema — это способ организовать и сгруппировать таблицы внутри catalog. Schema — средний уровень иерархии.
На что мапится schema, зависит от коннектора, и здесь кроется важная деталь. Коннектор переводит понятие «schema» в термины конкретного источника:
| Источник | Что Trino называет schema |
|---|---|
| PostgreSQL | PostgreSQL schema (public, analytics) |
| MySQL | MySQL database |
| Iceberg / Hive | namespace в metastore (Hive database) |
| Cassandra | Cassandra keyspace |
| MongoDB | MongoDB database |
То есть слово «schema» в Trino — это абстракция. В PostgreSQL она ложится один-в-один на родное понятие schema. В MySQL, где нет отдельного уровня schema внутри database, Trino мапит свою schema на MySQL database. Коннектор берёт на себя эту трансляцию — в этом и есть его работа.
Посмотреть схемы внутри catalog:
SHOW SCHEMAS FROM postgresql;
Schema
--------------------
analytics
information_schema
public
(3 rows)
Схема information_schema присутствует в каждом catalog — это стандартный ANSI-набор представлений с метаданными (список таблиц, столбцов, их типов). Trino поддерживает его повсеместно, независимо от источника.
Table: набор строк в типизированных столбцах
Table — это набор неупорядоченных строк, организованных в именованные типизированные столбцы. Это самый нижний уровень иерархии и единица, к которой обращается ваш SELECT.
Слово «неупорядоченных» здесь не случайно. Trino не гарантирует порядок строк в таблице без явного ORDER BY — как и SQL-стандарт. Физически данные могут лежать в множестве файлов на множестве нод, и читаться они будут параллельно.
Каждый столбец таблицы имеет тип. Типы Trino (BIGINT, VARCHAR, DECIMAL, TIMESTAMP, ARRAY, ROW и другие) — это собственная система типов движка. Коннектор отвечает за маппинг: он берёт родной тип источника (например, PostgreSQL int4) и сообщает Trino, что это integer. Когда вы делаете SELECT, происходит обратное преобразование.
Список таблиц и структуру конкретной таблицы:
SHOW TABLES FROM postgresql.public;
DESCRIBE postgresql.public.orders;
Column | Type | Extra | Comment
-------------+--------------+-------+---------
order_id | bigint | |
customer_id | bigint | |
total | decimal(10,2)| |
created_at | timestamp(6) | |
(4 rows)
Метаданные через ту же модель
Трёхуровневая модель используется не только для пользовательских данных, но и для самих метаданных Trino — и это хорошая иллюстрация её универсальности.
В каждом catalog есть схема information_schema — стандартный ANSI-набор представлений с метаданными. Это не выдумка Trino, а часть SQL-стандарта, и Trino поддерживает её для любого источника. Через неё можно запрашивать структуру как обычные таблицы:
-- Список столбцов всех таблиц схемы public — обычным SELECT
SELECT table_name, column_name, data_type
FROM postgresql.information_schema.columns
WHERE table_schema = 'public';
table_name | column_name | data_type
-------------+-------------+-----------
orders | order_id | bigint
orders | customer_id | bigint
orders | total | decimal(10,2)
customers | customer_id | bigint
customers | name | varchar(64)
(5 rows)
Команды SHOW TABLES, SHOW COLUMNS, DESCRIBE — это, по сути, удобные обёртки над запросами к information_schema. Удобно то, что метаданные доступны как данные: к information_schema.columns можно применять WHERE, JOIN, агрегации — например, посчитать, в скольких таблицах есть столбец с определённым именем.
Отдельно стоит catalog system — встроенный системный catalog, который есть всегда и не требует конфигурации. Он описывает не источники данных, а сам кластер Trino. Через него те же SELECT дают рантайм-информацию о движке:
-- Запущенные сейчас запросы — через системный catalog
SELECT query_id, state, query
FROM system.runtime.queries
WHERE state = 'RUNNING';
-- Ноды кластера
SELECT node_id, http_uri, coordinator
FROM system.runtime.nodes;
Схема system.runtime даёт таблицы queries (запросы), nodes (ноды), tasks (задачи) и другие. Это превращает наблюдаемость в обычный SQL: состояние кластера можно опрашивать тем же языком, что и пользовательские данные. И снова работает та же модель catalog.schema.table — system это catalog, runtime это schema, queries это table.
Запрос к information_schema или к system.runtime — быстрый способ исследовать незнакомый кластер. SELECT по system.runtime.nodes покажет, сколько воркеров в кластере; SELECT по information_schema.tables незнакомого catalog покажет все его таблицы, не дёргая SHOW по каждой схеме отдельно.
Зачем именно три уровня
Можно было бы спросить: почему три уровня, а не два или четыре? Ответ — в том, что три уровня покрывают реальную структуру практически любого источника данных при минимальной сложности.
Реляционные СУБД исторически имеют иерархию «сервер -> database/schema -> table». Object storage с табличными форматами имеет «metastore -> namespace -> table». NoSQL вроде Cassandra — «cluster -> keyspace -> table». Все эти модели укладываются в три уровня Trino: catalog поглощает понятие «инстанс источника», schema — «группа», table — собственно таблицу.
Эта унификация и есть фундамент федеративных запросов. Когда все источники приведены к одной трёхуровневой модели, движок может в одном SQL-запросе сослаться на таблицы из разных catalog — и для него это просто разные адреса:
-- Join таблицы из PostgreSQL и таблицы из Iceberg-на-S3 в одном запросе
SELECT c.name, SUM(o.total) AS revenue
FROM postgresql.public.customers AS c
JOIN iceberg.warehouse.orders AS o
ON o.customer_id = c.customer_id
GROUP BY c.name;
Trino видит здесь два полностью адресованных имени. Он понимает, что customers надо взять через коннектор PostgreSQL, а orders — через коннектор Iceberg, и сам организует чтение из обоих источников и их соединение. Без единой модели именования такой запрос был бы невозможен.
Чтобы не писать полное трёхуровневое имя в каждом запросе, в сессии задают catalog и schema по умолчанию: USE postgresql.public;. После этого SELECT * FROM orders неявно означает postgresql.public.orders. В Trino CLI это же делается флагами --catalog и --schema при запуске.
Попробуй сам
Возьмите любой работающий кластер Trino (подойдёт песочница курса в Docker) и подключитесь через CLI. Выполните по очереди:
SHOW CATALOGS;— выпишите все catalog. Найдите среди нихsystemи хотя бы один системный обучающий catalog вродеtpch.SHOW SCHEMAS FROM tpch;— посмотрите, какие схемы предлагает TPC-H. Обратите внимание на имена видаsf1,sf100— это масштабные факторы (scale factors).SHOW TABLES FROM tpch.sf1;и затемDESCRIBE tpch.sf1.orders;— изучите столбцы и их типы.- Выполните
SELECT * FROM tpch.sf1.nation;без указания catalog вUSE. Затем выполнитеUSE tpch.sf1;и повторитеSELECT * FROM nation;.
Запишите для себя: какой уровень иерархии задаёт коннектор, какой — конфигурация подключения, а какой существует уже внутри источника. Это разделение ответственности — ключ ко всему модулю.