> Как хранить историю изменений цен акций в базе данных (Go)
Уровень: senior · Роль: backend · Язык: Go · Категория: Технические вопросы
Компании: BrightPattern
Стек: Go
> Пример ответа
Короткий ответ
Для хранения истории цен акций оптимальна таблица с колонками ticker, price, timestamp и первичным ключом (ticker, timestamp). Это обеспечивает уникальность записей и эффективные запросы по временным диапазонам. Для высоконагруженных систем стоит рассмотреть партиционирование по времени и агрегацию старых данных. Индексы на timestamp и ticker обязательны. В Go используйте time.Time с часовым поясом UTC и decimal для цены.
Подробное объяснение
Основной trade-off - между гранулярностью данных и объемом хранения. Полная история тиков может генерировать миллионы записей в день на один инструмент. Поэтому архитектура обычно включает:
- Таблица тиков (raw data) - для последних N дней, с retention policy.
- Таблица свечей (OHLCV) - агрегированные данные за минуту/час/день для долгосрочного хранения.
- Таблица снапшотов - ежедневные снимки состояния (опционально).
Ключевые решения:
- Тип цены:
NUMERIC(18, 6)илиDECIMAL- никогда не используйте float/double из-за ошибок округления. - Временная метка:
TIMESTAMPTZв PostgreSQL илиDATETIME(6)в MySQL, всегда UTC. - Первичный ключ: композитный
(ticker, timestamp)- предотвращает дубликаты и ускоряет запросы по конкретному инструменту. - Партиционирование: по месяцам или неделям для облегчения удаления старых данных и ускорения сканирования.
- Сжатие: для старых данных можно использовать columnar storage (ClickHouse) или TimescaleDB.
На практике
Для Go-приложения с PostgreSQL:
- Используйте
pgxилиdatabase/sqlс пулом соединений. - Вставку делайте батчами (например, 1000 записей) через
COPYили multi-rowINSERT. - Для агрегации используйте материализованные представления или фоновые job'ы (например, через
pg_cron). - Настройте retention policy: удаление данных старше 90 дней из таблицы тиков, перенос в архив.
Пример схемы:
SQLCREATE TABLE price_ticks (ticker VARCHAR(10) NOT NULL,price NUMERIC(18, 6) NOT NULL,ts TIMESTAMPTZ NOT NULL,PRIMARY KEY (ticker, ts)) PARTITION BY RANGE (ts);CREATE TABLE price_ticks_2025_01 PARTITION OF price_ticksFOR VALUES FROM ('2025-01-01') TO ('2025-02-01');
Пример кода
Вставка батчем в Go:
GOfunc InsertPrices(ctx context.Context, db *sql.DB, ticker string, prices []PricePoint) error {tx, err := db.BeginTx(ctx, nil)if err != nil {return err}defer tx.Rollback()stmt, err := tx.PrepareContext(ctx,`INSERT INTO price_ticks (ticker, price, ts) VALUES ($1, $2, $3)`)if err != nil {return err}defer stmt.Close()for _, p := range prices {if _, err := stmt.ExecContext(ctx, ticker, p.Price, p.Timestamp); err != nil {return err}}return tx.Commit()}
Запрос последней цены:
GOSELECT price FROM price_ticksWHERE ticker = $1 AND ts <= $2ORDER BY ts DESC LIMIT 1;
Как отвечать на собеседовании
Начните с базовой схемы, затем уточните требования: частота обновления, объем данных, типы запросов. Покажите понимание trade-off между точностью и производительностью. Упомяните партиционирование, индексы и агрегацию. Если спросят про high-load - предложите TimescaleDB или ClickHouse. Подчеркните важность decimal для денежных значений и UTC для времени.
Что проверяет интервьюер
- Понимание нормализации и денормализации.
- Умение проектировать схему под нагрузку.
- Знание особенностей временных рядов (time-series).
- Владение SQL (индексы, партиции, оконные функции).
- Практический опыт с Go и БД.
Типичные ошибки
- Использование
floatдля цен - потеря точности. - Отсутствие композитного PK - дубликаты.
- Индекс только на
timestampбезticker- медленные запросы по конкретному инструменту. - Хранение всех данных без агрегации - быстрый рост БД.
- Игнорирование часовых поясов - смещение времени при анализе.
- Вставка по одной записи в цикле - низкая производительность.
> Похожие задачи по Go
Используется ли продукт конечными пользователями или это бета/альфа версия
Как решаются вопросы инфраструктуры и поддержки
Как организовать запись данных из WebSocket в базу данных и кэш
Как использовать паттерн outbox для обработки задержек записи в базу и обеспечения отказоустойчивости
> Похожие задачи по backend
Используется ли продукт конечными пользователями или это бета/альфа версия
Как решаются вопросы инфраструктуры и поддержки
Как организовать запись данных из WebSocket в базу данных и кэш
Как использовать паттерн outbox для обработки задержек записи в базу и обеспечения отказоустойчивости
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью