12 июля 2024 2110
Смотрим, как вездесущий PostgreSQL справляется с нестандартными для реляционной системы управления базами данных (СУБД) ролями: хранением и поиском временных рядов, пар «ключ — значение», эмбеддингов для больших языковых моделей и многомерных кубов.

PostgreSQL — один за всех? Как работать с нетипичными данными в реляционной системе



Смотрим, как вездесущий PostgreSQL справляется с нестандартными для реляционной системы управления базами данных (СУБД) ролями: хранением и поиском временных рядов, пар «ключ — значение», эмбеддингов для больших языковых моделей и многомерных кубов. Отвечаем на вопрос: действительно ли так нужно строить сложные архитектуры со множеством разнородных систем хранения данных — MongoDB, Redis, InfluxDB, Pinecone, ClickHouse, Apache Cassandra — или можно обойтись одним PostgreSQL?

Привет, Хабр! Меня зовут Александр Брейман, я доцент департамента программной инженерии факультета компьютерных наук НИУ ВШЭ и по совместительству эксперт Учебного центра IBS по управлению данными и архитектуре ПО. В прошлой статье я рассказывал о миграции с Oracle на PostgreSQL, а сегодня разберу, как последний работает с нетипичными видами данных.


Предыстория реляционных СУБД

Начну немного издалека. Разработка первой в истории базы данных началась в США в 1950-е годы. Как водится, заказчиком инновации был военно-промышленный комплекс. В ответ на появление в СССР дальних бомбардировщиков и ядерных бомб Пентагон решил разработать объединенную систему ПВО, в рамках которой актуальные данные обо всем, что происходит в небе, должны были собираться так, чтобы быть сразу доступными для принятия оперативных решений, например, о подъеме истребителей для перехвата цели. Вот это место, куда сразу поступают все имеющиеся данные, и назвали базой данных.



Схема проекта. Источник: http://www.fortwiki.com/File:Sage_Data_Flow.jpg

В основе такой базы данных лежали следующие принципы:

  • одна единая база данных на всю страну;

  • писатели вносят имеющиеся у них данные один раз;

  • читатели видят всегда актуальные данные;

  • для пользователей с разными задачами создаются отдельные представления (view).

Проект под кодовым названием SAGE сначала предложили IBM, но компания отказалась по причине нехватки программистов. На тот момент в IBM работало порядка 200 разработчиков, а проект, по их оценке, требовал привлечения тысяч специалистов. В результате под проект создали отдельную компанию — System Development Corporation. В разное время над SAGE работали до 7 000 человек.

К чему я завел этот разговор? Позже для разработки программ, обращающихся к базам данных, пришлось нанимать программистов, далеко не все из которых обладали глубоким математическим бэкграундом. Первые СУБД — это библиотеки подпрограмм, умеющие перемещать данные между памятью и файлами. Структура хранения в них либо очень простая — текст, либо похожая на структуры данных в памяти — списки и указатели. Проблема в том, что разработчики вынуждены были писать низкоуровневый сложный и очень хрупкий код, крошечная ошибка в котором могла полностью разрушить весь набор данных, а не только ту запись, к которой он обращался.

Собственно, именно эту проблему и были призваны решить реляционные СУБД (понятие «реляционный» основано на англ. relation — «отношение, зависимость, связь»). Эта концепция, скрывающая физический уровень хранения от разработчиков, которые теперь работают с более высокоуровневым и защищенным логическим представлением, была придумана в IBM в конце 1960-х математиком Эдгаром Коддом. Вместо указателей в реляционной модели — значения в столбцах таблицы. Связь строк идет только через совпадение значений, без каких-либо «физических» указателей.

Эдгар Кодд описал 12 правил, «Codd's 12 rules», которым должна удовлетворять реляционная СУБД. Хотя на самом деле их 13, потому что исчисление начинается с нуля. Вот эти правила:

0. Система должна быть способной управлять базами данных, используя исключительно свои реляционные возможности.

1. Вся информация в базе данных на логическом уровне должна быть явно представлена единственным способом: значениями в таблицах.

2. Каждое отдельное значение данных должно быть логически доступно с помощью комбинации имени таблицы, имени столбца и значения первичного ключа.

3. Неизвестные или отсутствующие значения NULL, должны поддерживаться для всех типов данных при выполнении любых операций.

4. Словарь данных должен сохраняться в форме реляционных таблиц, и СУБД должна поддерживать доступ к нему при помощи стандартных языковых средств.

5. Система должна поддерживать полноту подмножества языка.

6. Каждое представление (view) должно поддерживать все операции манипулирования данными: выборку, вставку, изменение и удаление.

7. Высокоуровневые операции вставки, изменения и удаления данных должны поддерживаться по отношению к любому множеству строк.

8. Приложения не должны зависеть от используемых способов хранения данных на физических носителях.

9. Представление данных в приложении не должно зависеть от структуры реляционных таблиц.

10. Вся информация, необходимая для поддержания и контроля целостности, должна находиться в словаре данных.

11. На работу приложения не должно влиять физическое расположение базы данных.

12. Разноуровневые языки доступа к данным должны быть согласованы между собой.


Проще говоря, мы видим следующие ключевые принципы:

  • разделение логической и физической структуры базы данных;

  • логическая структура: никаких указателей и ссылок;

  • только таблицы, строки которых имеют одинаковую структуру;

  • связь строк в разных таблицах: одинаковое значение в соответствующих столбцах;

  • язык, позволяющий выразить сложные составные запросы;

  • физическая структура — НЕ копия логической структуры, может быть очень сложной.

Позже к требованиям Кодда добавили еще одно — транзакционность. Система управления базами данных должна уметь выполнять группы операций — транзакции — так, чтобы при любом сбое в этом процессе откатываться к исходному состоянию и чтобы никаких следов от попытки выполнения не оставалось.

Главная проблема реляционных СУБД

Как это часто бывает, проблемы проистекают из особенностей решения. Слабое место реляционных баз данных — это масштабирование. Транзакции реализуются в СУБД локальным журналом или версионированием записей, а делать его глобальным или распределенным довольно сложно.

Чтобы решить эту проблему, а заодно и повысить отказоустойчивость, были придуманы специальные механизмы — шардирование и репликация.

Шардирование

Шардирование — это горизонтальное масштабирование кластера, когда отдельные части одной базы данных (шарды) размещаются на разных узлах.




При таком подходе возможна параллельная запись данных в несколько шардов, а их независимое друг от друга расположение защищает от одновременного отказа «всего и сразу». Тем не менее при отказе даже одного узла хранившаяся на нем часть данных становится недоступной. С этим можно бороться другим механизмом — репликацией.

Репликация

Репликация — это автоматическое копирование данных между несколькими узлами. Реплика — это копия данных.




Репликация повышает отказоустойчивость системы и обеспечивает параллельное чтение данных. Ограничения подхода возникают в том случае, если запрашиваемый узел, на который планируется копирование данных, по какой-то причине не отвечает. Тогда другой узел может либо пытаться «достучаться» до него, и тогда время выполнения записи удлиняется на длительность такого ожидания, либо сохранить данные у себя и отрапортовать об успехе операции, рискуя несогласованностью реплик. Более строго и подробно эта идея описана в виде CAP-теоремы.

Шардирование и репликация

Обычно используются вместе:



Сделать кластер из реляционных баз данных c шардированием и репликацией — не такая уж сложная задача, но ее приходилось реализовывать каждой компании самостоятельно. Например, Google с середины 1990-х годов хранил все свои данные — и поисковый индекс, и почту, и карты — в кластерах MySQL и полностью перешел на собственные технологии типа Spanner только после 2013 года. Сами реляционные системы стали предоставлять эти механизмы «из коробки» совсем недавно. Например, в Oracle шардирование появилось только в 2018 году, а в PostgreSQL оно полноценно реализовано только в платном Postgres Pro Shardman.

Альтернативные системы хранения данных

А до тех пор разработчики пытались найти замену «несовершенной» реляционной модели. Так, в конце 2000-х годов на арену вышли другие системы управления базами данных класса NoSQL, например MongoDB. Ее разработчики предложили автоматическое шардирование с репликацией, пусть и с предварительной настройкой, прямо «из коробки».

В класс NoSQL входят такие распространенные типы систем, как «ключ — значение», документные, графовые и объектно ориентированные системы. Все эти СУБД, а также временные ряды, поисковые движки и векторные базы данных были придуманы в свое время как способ нивелировать недостатки реляционных СУБД, в первую очередь — плохо выявляемые сбои в больших кластерах при использовании consumer-grade оборудования и открытого ПО без специальных требований к надежности, а также ошибки в архитектуре систем, использующих высоконормализованные реляционные модели данных.


Нетипичные данные и способы расширения PostgreSQL

Однако реляционные базы данных вообще и PostgreSQL в частности не стоят на месте. Сегодня различные расширения СУБД позволяют решать большинство задач, не прибегая к «зоопарку» из множества различных систем. Рассмотрим работу с отдельными видами нетипичных — то есть нетабличных — данных.


Как хранить и искать документы

В упомянутой выше модели «ключ — значение» часть данных мы считаем ключом, по которому можно искать и записывать определенный массив байтов. У такой модели максимально простой API с тремя базовыми операциями: put, get и delete.

Документ — это, по сути, вариант значения в модели «ключ — значение», но с дополнительными возможностями. К документу можно обращаться по его частям — полям, можно использовать специальные функции, например XPath для XML, автоматически валидировать данные, строить индексы по полям, а не только осуществлять поиск по ключу, и проводить специальные операции. Подобные возможности реализованы в том же MongoDB.

В PostgreSQL похожие вещи пытались сделать еще в конце 1990-х, но приличный результат получился только в 2014 году за счет реализации типа JSON. Сегодня Postgres предлагает для работы с документами JSONB и JSONPATH.

JSONB — это тип данных, он позволяет разобрать текстовый документ при записи и затем хранить его в бинарном формате. Примитивные типы при этом отображаются в типы PostgreSQL: text, numeric и boolean. JSONB предоставляет множество функций для создания и обработки документов, дополнительные операторы для обращения к ключам и вложенным элементам, а также возможность индексирования по всему документу или по отдельным ключам.

Что касается JSONPATH, это язык выборки частей документов, созданный по мотивам языка выделения частей XML-документов XPath, позволяющий декларативно описать маршрут внутри документа, по которому нужно пройти, чтобы получить нужные элементы. Например, можно выбрать поле с некоторым именем, не зная заранее, на каком уровне вложенности оно находится.

Первые релизы JSONB обладали некоторыми ограничениями, но в 2021 году схему хранения ощутимо улучшили, и операции теперь выполняются заметно быстрее. На сегодняшний день JSONB — полноценная рабочая замена MongoDB. Пожалуй, единственное преимущество MongoDB в данном случае — простота масштабирования, в первую очередь за счет шардирования. Если вы берете Postgres Pro Shardman, то для вас смысл работы с MongoDB пропадает совсем. Если же вы «сидите» на бесплатной версии PostgreSQL, то вопрос с документами «из коробки» получится решить только локально.

Как хранить и работать с временными рядами

Временной ряд — это последовательность измерений некоторого параметра. Речь может идти, например, о температуре, давлении, перемещениях такси, финансовых транзакциях, биржевых данных или звонках в кол-центр. Каждый элемент временного ряда содержит метку времени и значение. В отличие от многих других баз данных запросы к базам данных временных рядов очень редко обращаются к одной записи и, как правило, содержат агрегацию. Например: выведи среднее, максимальное и минимальное значение температуры с указанного датчика за каждую минуту последнего часа.

В PostgreSQL для работы с временными рядами применяется опенсорсное решение TimescaleDB. Суть подхода в том, что создается так называемая гипертаблица, то есть таблица, автоматически секционированная по столбцу с меткой времени в соответствии с заданным интервалом, например по часу на секцию. Каждая секция при этом хранится и индексируется отдельно, а по истечении заданного периода «холодные» секции, в которые уже больше не будут добавляться записи, сжимаются для более компактного хранения. Среди других удобных особенностей решения — политика автоматического удаления устаревших данных, распределенное хранение секций с репликацией и наличие специализированных гиперфункций.

Выглядит это примерно так:

CREATE TABLE conditions(

 tstamp timestamptz NOT NULL,

 device VARCHAR(32) NOT NULL,

 temperature FLOAT NOT NULL);

SELECT create_hypertable(

 'conditions', 'tstamp',

 chunk_time_interval => INTERVAL '1 day'

);

SELECT create_hypertable(

 'conditions', 'tstamp',

 partitioning_column => 'device',

 number_partitions => 8,

 chunk_time_interval => INTERVAL '1 day');

В данном примере временной интервал — один день, в течение которого система делит данные на восемь отдельных секций в зависимости от устройства, с которого поступает соответствующая информация.

В целом TimescaleDB прекрасно работает с временными рядами. Вообще, баз данных с временными рядами не так много. Пожалуй, ближайший открытый конкурент TimescaleDB в этой области — это ClickHouse. Оба решения по-своему хороши, и чтобы понять, какое из них будет лучше работать на ваших данных и ваших запросах, лучше попробовать оба и принять решение по итогам пилота.

Как хранить эмбеддинги и быстро их искать

Еще один тип данных, плохо приспособленных для реляционных СУБД, — это векторы. Каждая запись в векторной базе данных — это большой массив из чисел, или вектор в многомерном пространстве. Типичный запрос к такой базе: по заданному вектору найти векторы, наиболее близкие к нему. Определить близость векторов можно разными способами, например через косинусную меру или евклидово расстояние. Полноценный ответ на запрос в неспециализированных системах требует перебора всех хранящихся векторов, поскольку традиционные индексы — B-tree и Bitmap — не в силах эффективно ускорить решение такой задачи.

Сама по себе история с векторами сейчас предельно популярна, поскольку она используется при работе с большими языковыми моделями типа ChatGPT в рамках подхода retrieval augmented generation (RAG). В больших языковых моделях заложено кодирование текста/токенов в такие вектора — эмбеддинги. Мы можем закодировать все документы в виде эмбеддингов и сохранить их в базе данных, а затем так же закодировать запрос и найти ближайшие к нему эмбеддинги. После извлечения ближайших по смыслу документов, мы добавляем их к промпту для обогащения контекста запроса и передаем его в большую языковую модель. На подходе RAG сейчас строится много расширений нейронных сетей, что привело к всплеску популярности векторных баз данных. Таким же образом, кстати, в векторных базах можно искать изображения или звуки, строить рекомендации, а также находить аномалии, то есть обнаруживать отсутствие достаточно близких векторов.

В PostgreSQL для всего этого есть простое расширение pgvector. Оно работает с типом данных vector и предоставляет два алгоритма поиска — IVFlat и HNSW, — из которых нужно выбрать при создании таблицы. Один из них более быстрый, менее требовательный к памяти, но менее точный, а другой — точнее, но медленнее и ресурсозатратнее. По сути, они кластеризируют вектора, а затем осуществляют перебор в небольших кластерах.

Синтаксически это выглядит так:

select text, embedding <=> (

 select embedding from t where text = ‘??'

 ) distance

from t

order by distance;

Стоит сказать, что векторных баз сегодня представлено множество, включая такие многомиллионные стартапы, как Pinecone и Qdrant. PostgreSQL с расширением pgvector, — вполне достойный вариант. Основным ограничением будет все то же масштабирование.

Как строить многомерные кубы

Последняя специфическая история, не предназначенная для реляционных баз данных, — это многомерные кубы. Они были придуманы как инструмент для построения отчетов в хранилище данных, рассчитанный на НЕпрограммистов. Чтобы непрограммисты не напортачили в базе данных, им предоставили специальные витрины на многомерных кубах. Технология интерактивной аналитической обработки данных OLAP (online analytical processing) заключается в подготовке агрегированной информации на основе больших массивов данных, структурированных по многомерному принципу. Витрины данных позволяют пользователям самостоятельно описывать запросы и вид отчетов с помощью простого интерфейса и снижают риск перегрузки базы неоптимальными запросами

В языке SQL для реализации OLAP-сценариев в реляционных базах данных стандартные расширения были добавлены уже четверть века назад. Это GROUP BY ROLLUP, GROUP BY CUBE и GROUP BY GROUPING SETS. Расширения позволяют построить витрину по исходным данным и дальше сделать интерфейс.


Вердикт

Реляционные базы были ответом на очень важную потребность индустрии — отвязать физический уровень хранения от логического и набрать сотрудников, которые смогут писать запросы к базе данных на логическом уровне, не рискуя ее поломать. Эту простоту логики нам и подарили реляционные базы, и отказываться от нее на сегодняшний день было бы странно. Добавление NoSQL-решений, которые справлялись с нетипичными для реляционных баз данными, но не отличались простотой языка, имело смысл в нулевых годах. Но сегодня реляционные СУБД, включая PostgreSQL, уже откликнулись на волну NoSQL и внедрили ряд инструментов, которые позволяют справляться с большинством задач, включая полнотекстовый поиск, работу с временными рядами и даже векторными данными. Конечно, в устройстве этих инструментов придется сначала разобраться, но это определенно проще, чем использовать новую СУБД под каждый тип задачи и нанимать штат специалистов, разбирающихся в их устройстве. Оригинал статьи размещен на ХАБРе.





Последние статьи в блоге

Сквозная логика: от бизнес-процесса к реализации без потерь

Главный принцип работы с проектной документацией — поддерживать её связность и актуальность. Любая, даже самая детальная схема (BPMN, Use Case, C4), мгновенно теряет ценность, если она конфликтует с другой. Узнаёте? Сначала все силы бросают на «личный кабинет», но после пары спринтов главным внезапно становятся «возвраты». В результате возникает опасный разрыв: цели проекта, реализуемый функционал и схемы, которые должны их описывать, живут своей жизнью. Документация превращается в «мёртвые зоны», которые больше не отражают реальность.

29 августа 2025

Заказная разработка ПО в IBS: безопасная разработка и доставка

В этой статье начальник отдела DevOps компании IBS Артур Галеев расскажет об опыте внедрения принципов безопасной разработки, используемых инструментах и нормативных актах, на которые стоит опираться.

Новости
26 августа 2025

Сертификация ИТ-специалистов: точная оценка ваших компетенций

В ИТ-мире важно не просто обладать знаниями, но и четко понимать свой реальный уровень владения теми или иными навыками.

Новости
22 августа 2025

Группа компаний IBS запускает национальную сертификацию для бизнес-аналитиков

Центр сертификации IBS запускает новую систему оценки квалификации бизнес-аналитиков, которая сочетает международные стандарты c особенностями российского рынка. Программа ориентирована на теоретическую базу и прикладные навыки, необходимые в работе бизнес-аналитика в современных ИТ- и цифровых проектах.

Жизнь компании
20 августа 2025

От разработчика к тренеру: как превратить экспертизу в стабильный доход

Часто к преподаванию переходят после достижения «карьерного потолка»: на уровне сеньора процессы отлажены, и новые вызовы исчезают. Однако вместо того чтобы долго преподавать за символическую плату, можно сосредоточиться на создании системного заработка. Разберём реальные способы: от коучинга до запуска курсов.

Новости
13 августа 2025

Установка и настройка брокера сообщений Kafka на Windows

Цель задания: научиться устанавливать и настраивать Apache Kafka на операционной системе Windows, а также выполнять базовые операции с топиками и сообщениями.

21 июля 2025

Почему Python? Полный разбор Python vs Java в ML

«Когда 9 из 10 курсов по машинному обучению используют Python — это не случайность. Это результат десятилетия эволюции инструментов, сообщества и образовательной экосистемы».

21 июля 2025

Что должен знать и уметь архитектор ПО в 2025 году

Представьте профессию, в которой нужно одновременно мыслить как инженер, говорить как консультант и чувствовать бизнес как продакт. Архитектор ПО — это не просто старший разработчик с модным названием должности, а человек, который соединяет технологии, людей и цели в устойчивую, масштабируемую систему. Но какими навыками он должен владеть сегодня, чтобы быть действительно востребованным?

21 июля 2025

Памятка по документированию архитектурных решений

Отсутствие качественного архитектурного описания в сложных ИТ-проектах создает серьезные риски: фрагментированное понимание системы, накопление «архитектурного долга», трудности интеграции, масштабирования и онбординга. Это ведет к срывам сроков, перерасходу бюджета, снижению качества и росту затрат на поддержку, подвергая проект риску неоптимальных решений и критических уязвимостей.

Новости
18 июля 2025

Летняя акция: учитесь онлайн с выгодой, не выходя из отпуска! До конца августа второй курс со скидкой 50%

Проведите лето с пользой для карьеры – второй курс со скидкой 50%!

09 июля 2025

5 курсов июля со скидкой 30%

Друзья, у нас остались последние места на курсах, которые стартуют в июле. Сейчас есть возможность записаться на обучение со скидкой 30%!

Новости
04 июля 2025

Карьерный трек аналитика: от базы к экспертизе

Системные и бизнес-аналитики аналитики играют ключевую роль в digital-развитии продуктов. Эти специалисты выступают связующим звеном между бизнес-задачами и техническими решениями, обеспечивая эффективную коммуникацию между заинтересованными сторонами. Рассмотрим карьерные пути в аналитике, актуальные требования рынка и перспективы профессионального роста.

27 июня 2025

Почему именно сейчас стоит учиться на бизнес-аналитика уровня Middle. «Руководство BABOK» в подарок участникам программы!

Вы в ИТ, вам за 30. Вроде бы всё хорошо — есть работа, скиллы, стабильность. Но в воздухе — тревожность. Проекты замораживаются. Бизнес урезает бюджеты. От ИТ ждут не просто задач, а конкретного влияния на прибыль.

25 июня 2025

Уничтожит ли ИИ-генератор кода профессию разработчика?

С появлением ИИ-инструментов, а также в связи недавним анонсом Canva Code, который генерирует код за пару кликов, многие задумались: не станут ли такие инструмент угрозой для разработчиков? Давайте разберемся, есть ли здесь реальные риски, или это все же преувеличения.

23 июня 2025

Проектное резюме консультанта 1С: карьерный инструмент, чтобы выделиться среди других кандидатов

Рассказываем о продвинутой альтернативе привычного резюме для консультантов 1C и других специалистов с проектной занятостью.

Новости
19 июня 2025

Выбор карьеры: Менеджер бизнес-процессов или Бизнес-аналитик уровня Middle?

В мире цифровой трансформации пути развития аналитиков и менеджеров проектов все чаще расходятся: кому-то ближе работа с требованиями и API, а кому-то — выстраивание системной эффективности на уровне всей компании. Какой путь выбрать лично вам?

Новости
18 июня 2025

В Учебном центре IBS планируется запуск курсов по продуктам TData

Читайте о стратегическом соглашении TData и IBS и наших новых курсах

11 июня 2025

Компетенции бизнес-аналитиков: Junior и Middle в сравнении

В условиях динамично развивающейся ИТ-индустрии важно чётко понимать, какие навыки и знания необходимы для успешной работы на каждом этапе карьерного пути. Сегодня обсудим разницу в компетенциях ИТ бизнес-аналитиков уровней Junior и Middle. Если вы только начинаете свой путь в ИТ бизнес-анализе или, наоборот, уже обладаете некоторым опытом, этот материал поможет вам понять, какие навыки необходимы на каждом уровне и как развиваться дальше.

Новости
05 июня 2025

Лимит на сбои. Как понять, что система перегружена, а не просто плохо сделана?

Оценить производительность системы непросто, а контролировать еще сложнее. Как сделать так, чтобы внедряемая или уже эксплуатируемая система справлялась с нагрузками? Можно ли в этом вопросе полностью положиться на разработчиков ПО или вендоров? И кто в итоге будет отвечать за все простои системы? Рассказывает Николай Марченко, директор отделения нагрузочного тестирования компании IBS. Начать следует с того, что разбираться с последствиями возможных сбоев в любом случае придется тем, кто работает непосредственно с системой. Поэтому о вопросах производительности лучше задуматься еще на этапе внедрения.

Новости
03 июня 2025

Кто такой аналитик 1С?

Аналитик 1С — это специалист, который занимается оптимизацией бизнес-процессов с использованием программного обеспечения 1С. Его задача — анализировать существующие процессы, выявлять недостатки и разрабатывать решения для повышения эффективности. Аналитик переводит бизнес-требования в технические задания для разработчиков, становясь мостом между пользователями и ИТ-отделом. Эта роль требует как технических знаний, так и навыков коммуникации, что позволяет вносить значительный вклад в развитие компании и улучшение её конкурентоспособности.

Новости
28 мая 2025

Не нашли, что искали? — Просто напишите, и мы поможем

Корпоративное обучение Оценка персонала Сертификация О нас Стань тренером Блог
Пользователь только что записался на курс ""
Спасибо!
Форма отправлена успешно.