-- +goose Up -- Часовой объект — единица хранения разобранных точек. Строка на точку дала бы -- десятки миллионов строк в год; час даёт ~260 тысяч на слой независимо от -- плотности потока. -- -- Внутрь payload средствами SQL не заглянуть — это осознанная плата. Границы -- содержимого и счётчик вынесены колонками, чтобы каталог разрезов не разжимал -- каждый блоб ради диапазона. CREATE TABLE bucket ( metric TEXT NOT NULL, -- Слой выводится из выравнивания меток, а не из заголовка доставки: -- sample / raw / minute / hour / day. layer TEXT NOT NULL, -- Начало часа в UTC, RFC 3339. Час берётся по НАЧАЛУ точки: интервал -- пересекает границы часов, и любой другой выбор сделал бы принадлежность -- объекту зависящей от длительности. hour_utc TEXT NOT NULL, -- Единицы измерения живут на уровне метрики, внутри точки их нет (проверено -- на 89 доставках: поле units не встретилось ни разу). Без этой колонки -- единицы метрики, переставшей приходить, теряются навсегда. units TEXT NOT NULL DEFAULT '', -- Точки часа: JSON-массив исходных байтов точек, сжатый gzip. Точки -- упорядочены по времени начала. payload BLOB NOT NULL, -- Хеш канонической формы содержимого: детектор изменений, а не ключ. -- Совпал — записи не происходит, и широкие проходы синхронизации -- обходятся даром. content_hash TEXT NOT NULL, points INTEGER NOT NULL DEFAULT 0, -- Границы содержимого: первая и последняя метка начала, UTC RFC 3339. first_ts TEXT NOT NULL, last_ts TEXT NOT NULL, -- Провенанс: доставка, создавшая объект. Нужен, чтобы разбирать слияния; -- у отдельной точки провенанса нет и не будет. first_delivery_id TEXT NOT NULL DEFAULT '', -- Час, в который досчёт уже не ожидается. Правило перевода в sealed пока -- не определено — порог ставится по наблюдениям, которых нет; до тех пор -- признак остаётся невыставленным. sealed INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, PRIMARY KEY (metric, layer, hour_utc) ) WITHOUT ROWID; -- Каталог разрезов и Read API ходят «дай метрику за период»: метрика и слой -- уже в первичном ключе, но выборка по времени поверх всех метрик нужна -- ретеншену и проверке сходимости. CREATE INDEX bucket_hour_utc ON bucket (hour_utc); -- +goose Down DROP TABLE bucket;