[Перевод] Postgres в ретроспективе

habr.png

Предлагаем вашему вниманию перевод статьи Джозефа Хеллерштейна «Looking Back at Postgres», опубликованной в соответствии с международной лицензией Creative Commons «С указанием авторства» версии 4.0 (CC-BY 4.0). Авторы оставляют за собой право распространять эту работу на личных и корпоративных веб-сайтах с надлежащей ссылкой на источник.

Перевод выполнен Еленой Индрупской. От себя добавлю, что «программист, который отчаянно хотел построить систему с многоверсионностью» — судя по всему, Вадим Михеев, ну, а «добровольцев из России», переписавших GiST, мы все хорошо знаем.


Это воспоминание о проекте Postgres, выполняемом в Калифорнийском университете в Беркли и возглавляемом Майком Стоунбрейкером (Mike Stonebraker) с середины 1980-х до середины 1990-х годов. В качестве одного из многих личных и исторических воспоминаний, эта статья была запрошена для книги [Bro19], посвященной награждению Стоунбрейкера премией Тьюринга. Поэтому в центре внимания статьи — руководящая роль Стоунбрейкера и его мысли о дизайне. Но Стоунбрейкер никогда не был программистом и не мешал своей команде разработчиков. Кодовая база Postgres была работой команды блестящих студентов и эпизодически—штатных университетских программистов, которые имели немного больше опыта (и только немного большую зарплату), чем студенты. Мне посчастливилось присоединиться к этой команде в качестве студента в последние годы проекта. Я получил полезный материал для этой статьи от некоторых более старших студентов, занятых в проекте, но любые ошибки или упущения являются моими. Если вы заметили какие-либо из них, пожалуйста, свяжитесь со мной, и я постараюсь их исправить.
Postgres был самым амбициозным проектом Майкла Стоунбрейкера — его серьезной попыткой создать универсальную систему баз данных. Продолжаясь десятилетие, проект породил больше статей, кандидатов наук, профессоров и компаний, чем какая-либо еще деятельность Стоунбрейкера. Проект также охватывал больше технической области, чем любая другая система, которую он построил. Несмотря на риск, присущий такому масштабу, Postgres также стал самым успешным программным артефактом, который вышел из исследовательских групп Стоунбрейкера, и его основным вкладом в открытый исходный код. Это пример «второй системы» [Bro75], которая имела успех. На момент написания статьи, т. е. более тридцати лет с начала проекта, система PostgreSQL с открытым исходным кодом является в мире самой популярной независимой системой баз данных с открытым исходным кодом и четвертой по популярности системой баз данных. Между тем компании, созданные из Postgres, произвели в общей сложности более 2,6 млрд. долл. США (в стоимости приобретения). По любым меркам видение Postgres Стоунбрейкера имело огромный продолжительный резонанс.

1.1. Предыстория


Стоунбрейкер имел огромный успех в начале карьеры с исследовательским проектом Ingres в Беркли [SHWK76] и последующим стартапом, который он основал вместе с Ларри Роу (Larry Rowe) и Юджином Вонгом (Eugene Wong): Relational Technology, Inc. (RTI).

По мере развития RTI в начале 1980-х годов Стоунбрейкер начал работать над поддержкой в СУБД типов данных, выходящих за рамки традиционных строк и столбцов исходной реляционной модели Кодда (Edgar Frank Codd). Мотивирующим примером в то время была потребность поддержки базами данных инструментов автоматизированного проектирования (САПР) для микроэлектронной промышленности. В статье 1983 г. Стоунбрейкер и студенты Брэд Рубенштейн (Brad Rubenstein) и Антонин Гуттман (Antonin Guttman) объяснили, насколько эта отрасль нуждается в поддержке «новых типов данных, таких как многоугольники, прямоугольники, текстовые строки и т. д.», «эффективного пространственного поиска», «сложных ограничений целостности», а также «проектных иерархий и множественных представлений» в одних и тех же физических конструкциях [SRG83]. Имея такую мотивацию, группа начала работу над индексированием (в том числе с помощью R-деревьев Гуттмана для пространственного индексирования [Gut84]) и над добавлением абстрактных типов данных (АТД) в систему реляционных баз данных. В то время АТД были популярной новой конструкцией языков программирования, которая была впервые введена Барбарой Лисков (Barbara Liskov), впоследствии лауреатом премии Тьюринга, и исследована в прикладном программировании баз данных новым сотрудником Стоунбрейкера — Ларри Роу. В статье в SIGMOD Record в 1983 г. [OFS83] Стоунбрейкер и студенты Джеймс Онг (James Ong) и Деннис Фогг (Dennis Fogg) описывают исследование этого понятия в расширении Ingres, названном ADT-Ingres, в которое были включены многие концепции представления, изученные более глубоко и с лучшей системной поддержкой в Postgres.


Как следует из названия, Postgres это «Post-Ingres»: система, предназначенная для того, чтобы взять то, что могла делать Ingres, и выйти за ее рамки. Отличительным признаком Postgres было введение того, что он в конечном итоге назвал объектно-реляционными свойствами базы данных: поддержка концепции объектно-ориентированного программирования в модели данных и декларативного языка запросов системы баз данных. Но Стоунбрейкер также задумал решить в Postgres ряд других независимых от объектно-ориентированной поддержки технологических проблем, таких как правила активной базы данных, версионные данные, третичное хранилище и параллелизм.

Две статьи были написаны по дизайну Postgres: описание раннего дизайна в SIGMOD 1986 г. [SR86] и промежуточное описание в CACM 1991 г. [SK91]. Исследовательский проект Postgres постепенно «сошел на нет» в 1992 году с основанием Стоунбрейкером стартапа Illustra, в котором участвовали Стоунбрейкер, ведущий аспирант Вэй Хонг и позже ставший главным программистом Джефф Мередит (Jeff Meredith). В списке, приведенном ниже, возможности, упомянутые в статье 1986 года, отмечены звездочкой*, а возможности из статьи 1991 года, которых не было в статье 1986 года, — крестиком†. За другие задачи, перечисленные ниже, брались в системе и исследовательской литературе, но их нет ни в одной спецификации дизайна. Многие из этих тем рассматривались в Postgres задолго до того, как они были изучены или заново изобретены другими. Во многих случаях Postgres слишком опередил свое время, и интерес к темам вспыхнул позже, уже под современным углом зрения.

  1. Поддержка АТД в системе баз данных
    • Сложные объекты (т. е. вложенные данные или данные не первой нормальной формы (non-first-normal form — NF2))*
    • Пользовательские абстрактные типы данных и функции*
    • Расширяемые методы доступа для новых типов данных*
    • Оптимизированная обработка запросов с дорогостоящими пользовательскими функциями
  2. Активные базы данных и системы правил (триггеры, предупреждения)*
    • Правила, реализованные в виде перезаписи запроса†
    • Правила, реализованные как триггеры уровня записи†
  3. Хранение и восстановление на основе журнала
    • Код восстановления с уменьшенной сложностью, рассматривающий журнал как данные*, использование энергонезависимой памяти для состояния фиксации†
    • Хранилище без перезаписи и темпоральные запросы†
  4. Поддержка новых технологий глубокого хранения данных, в особенности оптических дисков*
  5. Поддержка мультипроцессоров и специализированных процессоров*
  6. Поддержка различных языковых моделей
    • Минимальные изменения реляционной модели и поддержка декларативных запросов*
    • Доступ к «быстрому пути» из внутренних API в обход языка запросов†
    • Многоязычность†


Мы кратко обсудим вклад Postgres по каждой из этих позиций в его связи с последующими работами в области вычислений.

2.1. Поддержка АТД в системе баз данных


Четко сформулированной целью Postgres была поддержка новых объектно-реляционных свойств: расширение технологии баз данных, чтобы обеспечить преимущества как реляционной обработки запросов, так и объектно-ориентированного программирования. Со временем объектно-реляционная концепция, впервые появившиеся в Postgres, стала стандартной функциональностью в большинстве современных систем баз данных.

2.1.1. Сложные объекты


Довольно часто данные представляются в виде вложенных сущностей или «объектов». Классическим примером является заказ на покупку, который имеет вложенный набор продуктов, их количеств и цен. Религия реляционного моделирования диктовала, что такие данные должны быть реструктурированы и сохранены в формате без вложенности, используя несколько плоских таблиц объектов (заказы, продукты) с соединяющими их плоскими таблицами отношений (продукт_в_заказе). Типичная причина такого уплощения заключается в том, что оно уменьшает дублирование данных (т. к. продукт избыточно описывается во многих заказах на покупку), что, в свою очередь, позволяет избежать сложности или ошибок при обновлении всех избыточных копий. Но в некоторых случаях вы хотите сохранить вложенное представление, потому что это естественно для приложения (например, механизм компоновки схемы в САПР), а обновления редки. Этот спор о моделировании данных по крайней мере так же стар, как и реляционная модель.

Ключевым подходом Postgres было «усидеть на двух стульях» с точки зрения моделирования данных: Postgres сохранил таблицы как «самый внешний» тип данных, но позволил столбцам иметь «сложные» типы, включая вложенные кортежи или таблицы. Одна из его малораспространенных реализаций, впервые исследованная в прототипе ADT-Ingres, заключалась в том, чтобы разрешить задавать столбец табличного типа декларативно, как определение запроса: «Quel как тип данных» [SAHR84] (Quel — язык запросов Ingres. — Прим. пер.).

«Постреляционная» тема поддержки как декларативных запросов, так и вложенных данных вновь возникала на протяжении многих лет, часто порождаемая спорами о том, что лучше. Во времена Postgres в 1980-х и 1990-х годах некоторые группы, занимающиеся объектно-ориентированными базами данных, подхватили эту идею и развили ее в стандартный язык OQL, который затем перестал использоваться.

На рубеже тысячелетий декларативные запросы к вложенным объектам стали навязчивой идеей исследований для сегмента сообщества разработчиков баз данных в виде баз данных XML. Получившийся в результате язык XQuery (во главе с Доном Чемберлином (Don Chamberlin) — персоной SQL) обязан поддержке сложных объектов языку Postquel из Postgres. XQuery получил широкое распространение и использование в промышленности, но никогда не был популярен у пользователей. Сегодня эти концепции вновь рассматриваются в проектах языков запросов для модели данных JSON, популярной в браузерных приложениях. Как и OQL, в группах, которые первоначально отвергали декларативные запросы в пользу программирования, ориентированного на разработчиков (движение «NoSQL»), эти языки часто возникают как запоздалое дополнение исключительно из желания добавить запросы обратно в системы. В то же время по мере роста Postgres с годами (и перехода от языка запросов Postquel к версиям SQL, которые отвечают многим из рассматриваемых целей), он включил поддержку вложенных данных, таких как XML и JSON, в СУБД общего назначения, не требуя какого-либо значительного перепроектирования. Споры протекают с переменным успехом, а подход Postgres к расширению реляционной структуры с помощью расширений для вложенных данных не раз показал себя естественным конечным состоянием для всех сторон после того, как аргументы утихают.

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


В дополнение к предложению вложенных типов Postgres выдвинул идею ввести непрозрачные, расширяемые АТД, которые хранятся в базе данных, но не интерпретируются ядром. В принципе, это всегда было частью реляционной модели Кодда: целые числа и строки были традиционными, но на самом деле реляционная модель охватывает любые атомарные типы данных с предикатами. Задача состояла в том, чтобы обеспечить такую математическую гибкость и в программном обеспечении. Чтобы использовать запросы, которые интерпретируют эти объекты и манипулируют ими, прикладной программист должен иметь возможность регистрировать в системе определяемые пользователем функции (user-defined functions — UDF) для этих типов и вызывать эти функции в запросах. Также желательно, чтобы определяемые пользователем агрегатные (user-defined aggregate — UDA) функции суммировали коллекции этих объектов в запросах. Система баз данных Postgres была новаторской, всесторонне поддерживая эти возможности.

Зачем помещать такую функциональность в СУБД, а не в высокоуровневые приложения? Типичным ответом на этот вопрос было значительное преимущество в производительности кода, помещенного к данным, перед «вытягиванием» данных к коду. Postgres показал, что это вполне естественно в рамках реляционной среды: потребовались лишь небольшие изменения в каталоге реляционных метаданных и были созданы механизмы вызова стороннего кода, но синтаксис запросов, семантика и системная архитектура работали просто и элегантно.

Postgres немного опередил свое время в исследовании этой функциональности. В частности, в то время сообщество исследователей баз данных не особенно беспокоилось о последствиях для безопасности при загрузке небезопасного кода на сервер. Это стало восприниматься как проблема, когда технологию заметили в индустрии. Стоунбрейкер вывел на рынок Postgres в своем стартапе Illustra, который был приобретен Informix в значительной степени за его способность поддерживать пакеты расширений DataBlade, в том числе UDF. Informix с технологией, основанной на Postgres, и сильным предложением параллельных баз данных стала значительной угрозой Oracle. Oracle инвестировала значительные средства в негативный маркетинг рисков, связанных со способностью Informix запускать «незащищенный» пользовательский C-код. Некоторые относят гибель Informix к этой кампании, хотя финансовые махинации Informix (и последующее федеральное обвинение его тогдашнего генерального директора), безусловно, представляли собой более серьезные проблемы. Теперь, десятилетия спустя, все основные поставщики баз данных поддерживают выполнение пользовательских функций на одном или более языках, используя новые технологии защиты от сбоев сервера или повреждения данных.

Между тем, технологические стеки больших данных 2000-х годов, включая феномен MapReduce, который «много крови попортил» Стоунбрейкеру и ДеВитту (David DeWitt) [DS08], являются повторной реализацией идеи Postgres — пользовательского кода, размещенного в рамках запроса. Представляется, что MapReduce во многом сочетает идеи разработки программного обеспечения от Postgres с идеями параллелизма от таких систем, как Gamma и Teradata, с некоторыми незначительными инновациями вокруг перезапуска в процессе выполнения запроса для рабочих нагрузок с экстремальной масштабируемостью. Стартапы на базе Postgres, Greenplum и Aster, примерно в 2007 году показали, что распараллеливание Postgres может привести к чему-то гораздо более функциональному и практичному, чем MapReduce, для большинства клиентов, но в 2008 году рынок все еще не был готов к этой технологии. К настоящему времени, в 2018 году, почти каждый стек больших данных в основном обслуживает рабочую нагрузку параллельного SQL с UDF, что очень похоже на дизайн, который Стоунбрейкер с командой впервые использовали в Postgres.

2.1.3. Расширяемые методы доступа для новых типов данных


Реляционные базы данных развивались примерно в то же время, что и B-деревья, в начале 1970-х годов, и B-деревья помогли дать импульс мечте Кодда о «независимости от физического хранения данных»: индексирование B-деревьями обеспечивает уровень косвенности, который адаптивно реорганизует физическое хранилище, не требуя изменения приложений. Основным ограничением B-деревьев и связанных с ними структур было то, что они поддерживают только поиск по равенству и запросы одномерного диапазона. А что делать, если у вас есть запросы 2-мерного диапазона, типичные для картографии и приложений САПР? Эта проблема была известна во время Postgres, и R-дерево [Gut84], разработанное Антонином Гуттманом в группе Стоунбрейкера, было одним из самых успешных новых индексов, разработанных для решения этой проблемы на практике. Тем не менее, изобретение индексной структуры не решает для комплексных систем задачу поддержки в СУБД многомерных диапазонов. Возникает много вопросов. Можете ли вы легко добавить метод доступа, такой как R-деревья, в свою СУБД? Можете ли вы научить оптимизатор понимать, что указанный метод доступа будет полезен для определенных запросов? Вы можете добиться корректности восстановления и одновременного доступа? Это был очень смелый пункт программы действий Postgres: проблема архитектуры программного обеспечения, затрагивающая большую часть ядра базы данных, от оптимизатора до уровня хранения, а также системы журналирования и восстановления. R-деревья в Postgres стали мощной движущей силой и основным примером элегантной расширяемости уровня метода доступа и его интеграции в оптимизатор запросов. Postgres показал, способом непрозрачных АТД, как зарегистрировать абстрактно описанный метод доступа (в данном случае R-дерево), и как оптимизатор запросов может распознать абстрактный предикат выборки (в данном случае выбор диапазона) и сопоставить его с этим абстрактно описанным методом доступа. Вопросам управления одновременным доступом было уделено меньше внимания в первоначальной работе: отсутствие одномерного упорядочения ключей сделало в данном случае блокировку, применяемую в B-деревьях, неприменимой.

Многообещающие возможности расширяемых методов доступа Postgres вдохновили один из моих первых исследовательских проектов в конце аспирантуры: обобщенные деревья поиска (Generalized Search Trees—GiST) [HNP95] и последующую концепцию теории индексируемости [HKM+02]. Я реализовал GiST в Postgres в течение семестра после получения докторской степени, что сделало добавление новой логики индексирования в Postgres еще проще. В диссертации Марселя Корнакера из Беркли (Marcel Kornacker) решены сложные задачи восстановления и одновременного доступа, поставленные расширяемым «шаблонным» типом индекса GiST [KMH97].

Сегодня PostgreSQL выгодно сочетает оригинальную программную архитектуру расширяемых методов доступа (она имеет индексы B-tree, GiST, SP-GiST и Gin) с расширяемостью и интенсивным конкурентным доступом интерфейса обобщенного дерева поиска (GiST). Индексы GiST поддерживают популярную гео-информационную систему PostGIS на базе PostgreSQL. Индексы Gin обеспечивают внутреннюю поддержку индексирования текста в PostgreSQL.

2.1.4. Оптимизатор обработки запросов с дорогостоящими UDF


В традиционной оптимизации запросов задача состояла в том, чтобы свести к минимуму объем потока кортежей (и, следовательно, операций ввода-вывода), создаваемых при обработке запроса. Это означало, что операторы, которые фильтруют кортежи (выборка), хороши в начале плана запроса, в то время как операторы, которые могут генерировать новые кортежи (соединение), должны быть выполнены позже. В результате оптимизаторы запросов будут «выталкивать» операторы выборки ниже соединений и упорядочивать их произвольно, сосредотачиваясь вместо этого на умной оптимизации соединений и обращений к диску. UDF изменили подход: если у вас в операторах выборки дорогостоящие UDF, порядок выполнения UDF может иметь решающее значение для оптимизации производительности. Более того, если UDF в операторе выборки действительно занимает много времени, возможно, выборку следует выполнять после соединений (т. е. выполнить «подтягивание» выборки вверх — selection «pullup»). Учет этих факторов усложнил пространство поиска для оптимизатора. Я взял эту проблему как первую сложную задачу в аспирантуре, и кончилось тем, что она стала предметом моей магистерской работы со Стоунбрейкером в Беркли и моей кандидатской в Висконсине под руководством Джеффа Нотона (Jeff Naughton), но при постоянной помощи советами от Стоунбрейкера. СУБД Postgres была первой, которая сохраняла стоимость и избирательность пользовательских функций в каталоге базы данных. Мы подошли к задаче оптимизации, придумав оптимальный порядок операций выборки, а затем оптимальное чередование операций выборки вдоль ветвей каждого дерева соединений, рассматриваемого при поиске плана. Это позволило оптимизатору поддерживать архитектуру классического динамического программирования System R с небольшой дополнительной стоимостью сортировки для правильного упорядочения дорогостоящих операторов выборки.

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

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

По иронии судьбы, код, написанный мною в аспирантуре, был полностью удален из дерева исходных текстов PostgreSQL молодым программистом по имени Нил Конвей (Neil Conway), который несколько лет спустя начал делать кандидатскую диссертацию под моим руководством в Калифорнийском университете в Беркли и теперь является одним из «кандидатских внуков» Стоунбрейкера.

2.2. Активные базы данных и системы правил


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

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

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

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

Работа Стоунбрейкера над правилами баз данных началась с кандидатской работы Эрика Хэнсона (Eric Hanson), которая первоначально делалась для Ingres, но быстро переместилась в новый проект Postgres. Она была расширена в кандидатской работе Спироса Потамианоса (Spyros Potamianos) над PRS2: Postgres Rules System 2. Темой в обеих реализациях была возможность реализовать правила двумя различными способами. Один из них — трактовать правила как перезапись запросов. Это напоминает работу над перезаписью представлений, что впервые сделал Стоунбрейкер в Ingres. В этом сценарии логика правила «при условии выполнить действие» преобразуется в «при запросе перезаписать его и выполнить вместо исходного». Например, запрос типа «добавить новую строку к списку наград Майка» может быть переписан как «повысить зарплату Майка на 10%». Другой способ состоял в том, чтобы реализовать более естественное «при условии выполнить действие», проверяя условия на уровне строк с помощью блокировок внутри базы данных. При обнаружении таких блокировок результатом было не ожидание (как в традиционном управлении одновременным доступом), а выполнение соответствующего действия.

Код для правил уровня строк в PRS2 был, как печально известно, сложным. Небольшим поиском в архивах Postgres в Беркли был обнаружен следующий комментарий (вероятно, Спироса Потамианоса) к исходному коду Postgres версии 3.1 примерно 1991 года (дается в переводе):

* О П И С А Н И Е:
* Сделай глубоооокий вдох и прочти. Если ты не можешь не влезать в нижеследующий
* код (т. е. если босс не вынудил тебя добровольно делать это
* "грязное" дело) избегай этого любой ценой. Попробуй делать что-то менее опасное
* для твоего (психического) здоровья. Иди домой и посмотри фильмы ужасов по телевизору.
* Почитай немного Лавкрафта.  Пойди служить в армию.  Иди и проведи несколько ночей
* в народном парке. Соверши самоубийство...
* Что, продолжаешь читать, неужели? Хорошо, тогда ты заслуживаешь того, что получил.
* Добро пожаловать в мрачный лабиринт системы правил уровня кортежей, мой
* бедный коллега...


В итоге для реализации правил в Postgres ни метод перезаписи запросов, ни метод блокировки на уровне строк не были объявлены «победителями» — оба были сохранены в выпущенной системе. В конце концов код всех правил был забракован и переписан в PostgreSQL, но текущий исходный код по-прежнему сохраняет оба понятия триггеров на уровне операторов и на уровне строк.

Системы правил Postgres в свое время имели очень большое влияние и шли «ноздря в ноздрю» с исследованиями по проектам IBM Starburst и MCC HiPAC. Сегодня триггеры являются частью стандарта SQL и реализованы в движках многих основных баз данных. Однако они используются с некоторой осторожностью. Одна из проблем заключается в том, что наработки, о которых говорилось, так и не преодолели негативных моментов, которые привели к «зиме искусственного интеллекта»: взаимодействия в нагромождении правил могут стать неприемлемо запутанными, даже когда набор правил растет незначительно. Кроме того, на практике по-прежнему выполнение триггеров обычно занимает относительно много времени, поэтому внедряемые базы данных, которые должны работать быстро, как правило, избегают использования триггеров. Однако была некоторая кустарщина в смежных областях, таких как поддержка материализованных представлений, обработка сложных событий и потоковые запросы, каждая из которых в некотором роде является расширениями идей, исследованных в системах правил Postgres.

2.3. Xранение и восстановление на основе журнала


Стоунбрейкер описал свой дизайн системы хранения Postgres таким образом:

Обдумывая систему хранения Postgres, мы руководствовались миссионерским рвением сделать что-то необычное. Все современные коммерческие системы используют менеджер хранилища с журналом упреждающей записи (write-ahead log — WAL), и мы чувствовали, что эта технология хорошо понятна. Более того, оригинальный прототип Ingres 1970-х годов использовал аналогичный менеджер хранилища, и у нас не было желания делать другую реализацию. [SK91]

Хотя это выглядит, как чистая интеллектуальная неугомонность, были и технологические основания для этой работы. На протяжении многих лет Стоунбрейкер неоднократно выражал неприязнь к сложным схемам ведения журнала упреждающей записи, впервые разработанным в IBM и Tandem для восстановления баз данных. Одно из его основных возражений основано на интуиции разработчика программного обеспечения: никто не должен полагаться на что-то столь сложное, особенно для функциональности, которая будет использоваться только в редких, критических сценариях после сбоя.

Xранилище Postgres объединило понятия основного хранилища и журналирования исторической информации в единое простое дисковое представление. В своей основе идея заключалась в том, чтобы хранить каждую запись в базе данных в связанном списке версий, помеченных идентификаторами транзакций, — в некотором смысле это «журнал как данные» или «данные как журнал» в зависимости от вашей точки зрения. Единственные дополнительные метаданные, которые необходимы, — это список идентификаторов завершенных транзакций и времени их фиксации. Этот подход значительно упрощает восстановление, так как нет «перевода» из журнального представления обратно в основное представление. Он также делает возможными темпоральные запросы: вы можете выполнять запросы по состоянию на некоторый момент времени и получать доступ к версиям данных, которые были зафиксированы в это время. Первоначальный дизайн системы хранения Postgres, который выглядит так, как будто Стоунбрейкер описал его в одном творческом сеансе мозгового штурма, рассматривал ряд проблем эффективности и оптимизации базовой схемы наряду с грубым анализом того, как может повести себя производительность [Sto87]. Итоговая реализация в Postgres была несколько проще.

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

К сожалению, PostgreSQL все еще не особенно быстро обрабатывает транзакции: использование в нем журнала упреждающей записи несколько половинчато. Как ни странно, команда PostgreSQL сохранила много служебной информации, хранимой вместе с кортежами в Postgres, для обеспечения многоверсионности, что никогда не было целью проекта Postgres в Беркли. Результатом является система хранения, которая может эмулировать изоляцию снимков (snapshot isolation) Oracle с изрядным объемом дополнительных накладных расходов ввода-вывода, но которая не следует первоначальной мысли Стоунбрейкера о темпоральных запросах или простом восстановлении.

Майк Олсон (Mike Olson) отмечает, что его первоначальное намерение состояло в том, чтобы заменить реализацию B-дерева Postgres своей собственной реализацией B-дерева из проекта Berkeley DB, который разрабатывался в Беркли в эпоху Postgres. Но Олсон так и не нашел на это времени. Когда годы спустя Berkeley DB получила поддержку транзакций в Sleepycat Corp., Олсон попытался убедить (тогдашнее) сообщество PostgreSQL использовать его для восстановления вместо хранилища «без перезаписи». Они отказались: в проекте был программист, который отчаянно хотел построить систему с многоверсионностью (MVCC), и поскольку он был готов выполнить работу, он выиграл спор.

Медленно работающее хранилище PostgreSQL не является внутренне присущим системе. В Greenplum ветка PostgreSQL в качестве интересной альтернативы интегрировала высокопроизводительное сжатое хранилище. Оно было разработано Мэттом МакКлином (Matt McCline)—ветераном команды Джима Грея (Jim Gray) в компании Tandem. Оно также не поддерживало темпоральных запросов.

Но возможность темпоральных запросов была интересной и оставалась уникальной. Более того, кредо Стоунбрейкера в отношении разработки простого программного обеспечения для восстановления данных сегодня имеет отголоски как в контексте систем NoSQL (которые выбирают репликацию, а не WAL), так и в базах данных основной памяти (MMDB — main memory databases, которые часто используют многоверсионность и сжатые журналы фиксации). Идея версионных реляционных баз данных и темпоральных запросов сегодня все еще отнесена к эзотерике, появляясь в случайных исследовательских прототипах и небольших проектах с открытым исходным кодом. Это идея, которая созрела для возвращения в нашу эпоху дешевого хранения и непрерывных потоков данных.

2.4. Запросы к данным на носителях с новыми технологиями глубокого хранения


В середине проекта Postgres Стоунбрейкер подписался в качестве одного из руководителей на большой грант по научному направлению «цифровая земля» под названием Project Sequoia. Часть грантового предложения заключалась в обработке беспрецедентных объемов цифровых спутниковых изображений, требующих до 100 терабайт памяти, т. е. намного большего объема данных, чем в то время было бы разумно хранить на магнитных дисках. В основе предлагаемого решения было исследовать идею создания СУБД (а именно Postgres), облегчающей доступ к полуавтономному «третичному» хранилищу, предоставляемому роботизированными накопителями с автоматической сменой дисков для управления библиотеками оптических дисков или лент.

Из этого вытекало несколько разных исследований. Одним из них была файловая система Inversion — попытка предоставить абстракцию файловой системы UNIX над реляционной СУБД. В обзорной статье для Sequoia Стоунбрейкер описал это в своем обычном стиле свысока как «простое упражнение» [Sto95]. На самом деле Майк Олсон, студент Стоунбрейкера (и последующий основатель компании Cloudera), был занят этим в течение нескольких лет, да и конечный результат не был вполне однозначным [Ols93] и не выжил на практике.

На несколько лет позже Inversion Билл Гейтс «бился с теми же ветряными мельницами» в WinFS — попытке воссоздать наиболее широко используемую в мире файловую систему над серверной частью реляционной базы данных. WinFS поставлялась в разработческих версиях Windows, но так и не вышла на рынок. Гейтс позже назвал это своим самым большим в Microsoft разочарованием.

Друг

© Habrahabr.ru