Проще ли функциональное сопоставление с реляционным, чем объектно-реляционное?

StackOverflow https://stackoverflow.com/questions/218190

Вопрос

Объектно-реляционное сопоставление хорошо обсуждалось, в том числе и здесь.У меня есть опыт работы с несколькими подходами, а также с подводными камнями и компромиссами.Истинное разрешение, похоже, требует изменений в самих OO или реляционных моделях.

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

Есть ли у кого-нибудь какие-нибудь интересные мнения или озарения?Каково положение дел в отрасли?

Это было полезно?

Решение

Сложными проблемами расширения реляционной базы данных являются расширенные транзакции, несоответствия типов данных, автоматический перевод запросов и такие вещи, как N + 1 Выберите , которые являются фундаментальными проблемами выхода из реляционной системы и, на мой взгляд, не меняются при изменении парадигмы принимающего программирования.

Другие советы

Какова цель ORM?

Основная цель использования ORM - установить мост между сетевой моделью (ориентация объектов, графики и т.д.) и реляционной моделью.И главное различие между этими двумя моделями на удивление простое.Важно, указывают ли родители на детей (сетевая модель) или дети указывают на родителей (реляционная модель).

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

Как SQL может решить проблемы, возникающие у нас с ORMS?

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

  • Oracle (вероятно, самая сложная реализация)
  • PostgreSQL (в некоторой степени)
  • Информикс
  • SQL Server, MySQL и т.д.(посредством "эмуляции" с помощью XML или JSON)

На мой взгляд, если бы во всех базах данных был реализован стандарт SQL MULTISET() оператор (например,Oracle делает), люди больше не будут использовать ORM для отображения (возможно, все еще для сохранения графа объектов), потому что они могут материализовывать вложенные коллекции непосредственно из баз данных, напримерэтот запрос:

SELECT actor_id, first_name, last_name,
  MULTISET (
    SELECT film_id, title
    FROM film AS f
    JOIN film_actor AS fa USING (film_id)
    WHERE fa.actor_id = a.actor_id
  ) AS films
FROM actor AS a

Это привело бы к получению всех актеров и их фильмов в виде вложенной коллекции, а не денормализованного результата объединения (где актеры повторяются для каждого фильма).

Функциональная парадигма на стороне клиента

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

Однако, поскольку объектная ориентация в функциональных языках программирования менее идиоматична, у вас меньше шансов встроить каждый элемент данных в объект.Для кого-то, пишущего SQL, проецирующего произвольный кортежи это очень естественно.SQL использует структурную типизацию.Каждый SQL-запрос определяет свой собственный тип строки без необходимости предварительно присваивать ему имя.Это очень хорошо согласуется с функциональными программистами, особенно когда вывод типов является сложным, в случае чего вам никогда не придет в голову сопоставить ваш результат SQL с каким-либо ранее определенным объектом / классом.

Пример использования Java дЖУК из этого поста в блоге могло бы быть:

// Higher order, SQL query producing function:
public static ResultQuery<Record2<String, String>> actors(Function<Actor, Condition> p) {
    return ctx.select(ACTOR.FIRST_NAME, ACTOR.LAST_NAME)
              .from(ACTOR)
              .where(p.apply(ACTOR)));
}

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

// Get only actors whose first name starts with "A"
for (Record rec : actors(a -> a.FIRST_NAME.like("A%")))
    System.out.println(rec);

Абстракция FRM поверх SQL

Некоторые FRM пытаются абстрагироваться от языка SQL, обычно по следующим причинам:

  • Они утверждают, что SQL недостаточно скомпонован (jOOQ опровергает это, просто очень трудно разобраться правильно).
  • Они утверждают, что пользователи API больше привыкли к "родным" API коллекций, поэтому, например JOIN переводится на flatMap() и WHERE переводится на filter(), и т.д.

Чтобы ответить на ваш вопрос

FRM не "проще", чем ORM, он решает другую проблему.Фактически, FRM на самом деле не решает вообще никакой проблемы, потому что SQL, будучи сам по себе декларативным языком программирования (который не так уж сильно отличается от функционального программирования), очень хорошо подходит для других функциональных клиентских языков программирования.Таким образом, во всяком случае, FRM просто устраняет разрыв между SQL, внешним DSL и вашим клиентским языком.

(Я работаю в компании, стоящей за дЖУК, так что этот ответ предвзят)

Это зависит от ваших потребностей

  1. Если вы хотите сосредоточиться на структурах данных, используйте ORM, такой как JPA / Hibernate
  2. Если вы хотите пролить свет на методы лечения, загляните в библиотеки FRM:QueryDSL или Jooq
  3. Если вам нужно настроить свои SQL-запросы на конкретные базы данных, используйте JDBC и собственные SQL-запросы

Сильной стороной различных технологий "Реляционного отображения" является переносимость:вы гарантируете, что ваше приложение будет работать с большинством баз данных ACID.В противном случае вы будете иметь дело с различиями между различными диалектами SQL при написании SQL-запросов вручную.

Конечно, вы можете ограничиться стандартом SQL92 (а затем заняться некоторым функциональным программированием) или вы можете повторно использовать некоторые концепции функционального программирования с помощью фреймворков ORM

Силы ORM строятся на объекте сеанса, который может выступать в качестве узкого места:

  1. он управляет жизненным циклом объектов до тех пор, пока выполняется базовая транзакция базы данных.
  2. он поддерживает взаимно однозначное сопоставление между вашими объектами java и строками вашей базы данных (и использует внутренний кэш, чтобы избежать дублирования объектов).
  3. он автоматически обнаруживает обновления ассоциаций и ненужные объекты для удаления
  4. он обрабатывает проблемы параллелизма с помощью оптимистичной или пессимистичной блокировки.

Тем не менее, его сильные стороны являются одновременно и слабыми сторонами:

  1. Сеанс должен иметь возможность сравнивать объекты, поэтому вам нужно реализовать методы equals / hashCode.Но равенство объектов должно основываться на "Бизнес-ключах", а не на идентификаторе базы данных (новые временные объекты не имеют идентификатора базы данных!).Однако некоторые овеществленные концепции не имеют бизнес-равенства (например, операция).Распространенный способ обхода основан на идентификаторах GUID, которые, как правило, расстраивают администраторов баз данных.

  2. Сеанс должен отслеживать изменения отношений, но его правила отображения подталкивают к использованию коллекций, непригодных для бизнес-алгоритмов.Иногда вы хотели бы использовать HashMap, но ORM потребует, чтобы ключ был другим "Богатым доменным объектом" вместо другого легкого...Затем вы должны реализовать равенство объектов для объекта rich domain, действующего как ключ...Но вы не можете этого сделать, потому что у этого объекта нет аналогов в деловом мире.Таким образом, вы возвращаетесь к простому списку, который вам приходится повторять (и из-за этого возникают проблемы с производительностью).

  3. ORM API иногда непригодны для использования в реальном мире.Например, веб-приложения реального мира пытаются обеспечить изоляцию сеанса, добавляя некоторые предложения "WHERE" при извлечении данных...Тогда "Session.get(id)" недостаточно, и вам нужно обратиться к более сложному DSL (HSQL, Criteria API) или вернуться к собственному SQL

  4. Объекты базы данных конфликтуют с другими объектами, предназначенными для других фреймворков (например, OXM frameworks = Object / XML Mapping).Например, если ваши службы REST используют библиотеку jackson для сериализации бизнес-объекта.Но этот Джексон точно соответствует режиму гибернации.Затем либо вы объединяете оба и появляется сильная связь между вашим API и вашей базой данных , либо вы должны реализовать перевод, и весь код, который вы сохранили из ORM, там теряется...

С другой стороны, FRM - это компромисс между "Объектно-реляционным отображением" (ORM) и собственными SQL-запросами (с JDBC)

Лучший способ объяснить различия между FRM и ORM состоит в принятии подхода DDD.

  • Объектно-реляционное сопоставление расширяет возможности использования "Rich Domain Object", которые представляют собой классы Java, состояния которых изменяются во время транзакции базы данных
  • Функциональное реляционное сопоставление опирается на "Плохие объекты домена", которые являются неизменяемыми (настолько, что вам приходится клонировать новый каждый раз, когда вы хотите изменить его содержимое)

Он снимает ограничения, наложенные на сеанс ORM, и большую часть времени полагается на DSL поверх SQL (поэтому переносимость не имеет значения) Но, с другой стороны, вы должны изучить детали транзакции, проблемы параллелизма

List<Person> persons = queryFactory.selectFrom(person)
  .where(
    person.firstName.eq("John"),
    person.lastName.eq("Doe"))
  .fetch();

Я предполагаю, что функционал для реляционного отображения должен быть проще в создании и использовании, чем OO для RDBMS. Пока вы только запрашиваете базу данных, то есть. Я пока не понимаю (как), как вы могли бы делать обновления базы данных без побочных эффектов.

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

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

Довольно часто начинать с набора данных, выполнять на нем сложные вычисления и сохранять результаты, где, например, результаты представляют собой подмножество оригинала с дополнительными значениями. Императивный подход требует хранения исходного набора данных с дополнительными столбцами NULL, выполнения вычислений, а затем обновления записей с вычисленными значениями.

Кажется разумным. Но проблема в том, что это может быть очень медленным. Если ваши вычисления требуют другого оператора SQL помимо самого запроса на обновление или даже должны быть выполнены в коде приложения, вы буквально должны (повторно) искать записи, которые вы изменяете после вычисления, чтобы сохранить результаты в правильных строках .

Вы можете обойти это, просто создав новую таблицу для результатов. Таким образом, вы всегда можете вставить вместо обновления. В итоге получается еще одна таблица, дублирующая ключи, но вам больше не нужно тратить пространство на столбцы, хранящие NULL & # 8211; Вы храните только то, что имеете. Затем вы присоединяете свои результаты к своему окончательному выбору.

Я (ab) использовал СУБД таким образом и в итоге написал операторы SQL, которые выглядели в основном так ...

create table temp_foo_1 as select ...;
create table temp_foo_2 as select ...;
...
create table foo_results as
  select * from temp_foo_n inner join temp_foo_1 ... inner join temp_foo_2 ...;

То, что это делает, по сути, создает группу неизменных привязок. Хорошая вещь, однако, в том, что вы можете работать с целыми сетами одновременно. В некотором роде напоминает вам языки, которые позволяют вам работать с матрицами, например Matlab.

Я полагаю, что это также значительно упростит параллелизм.

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

Я думаю, что, как упомянул Сэм, для обновления БД необходимо столкнуться с теми же проблемами параллелизма, что и в мире OO. Функциональная природа программы может быть даже немного более проблематичной, чем природа объекта из-за состояния данных, транзакций и т. Д. СУБД.

Но для чтения функциональный язык мог бы быть более естественным для некоторых проблемных областей (как, кажется, независимо от БД)

Функциональное отображение < - > RDBMS не должно иметь больших отличий от отображений OO < - > RDMBS. Но я думаю, что это во многом зависит от того, какие типы данных вы хотите использовать, если вы хотите разработать программу с новой схемой БД или сделать что-то против устаревшей схемы БД и т. Д.

Ленивые выборки и т. д. для ассоциаций, например, могут быть реализованы довольно хорошо с некоторыми ленивыми концепциями, связанными с оценкой. (Хотя с OO их тоже можно сделать довольно красиво)

Изменить. С помощью поиска я нашел HaskellDB (библиотека SQL для Haskell) - что может стоить попробовать?

Базы данных и функциональное программирование могут быть объединены.

например:

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

               Clojure -> DBMS, Super Foxpro
                   STM -> Transaction,MVCC
Persistent Collections -> db, table, col
              hash-map -> indexed data
                 Watch -> trigger, log
                  Spec -> constraint
              Core API -> SQL, Built-in function
              function -> Stored Procedure
             Meta Data -> System Table

Примечание. В последней спецификации spec2 спецификация больше похожа на RMDB. см. spec-alpha2 вики: схема и выбор

Я выступаю за: построение реляционной модели данных поверх хэш-карты для достижения сочетания преимуществ NoSQL и RMDB. На самом деле это обратная реализация posgtresql.

Утиная печать: если она похожа на утку и крякает как утка, значит, это утка.

Если модель данных clojure, такая как RMDB, средства clojure, такие как RMDB, и манипулирование данными clojure, такие как RMDB, clojure должен быть RMDB.

Clojure - это функциональный язык программирования, основанный на теории реляционных баз данных

Все RMDB

Реализация модели реляционных данных и программирования на основе хэш-карты (NoSQL )

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top