Статьи

JOOQ vs. Slick — за и против каждого подхода

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

Примером того, где этот компромисс недавно поразил пользователей, является обсуждение « Являются ли запросы Slick в целом изоморфными запросам SQL? «. И, конечно же, ответ таков: нет. То, что кажется простым Slick-запросом:

1
2
3
4
5
6
7
8
9
val salesJoin = sales
      join purchasers
      join products
      join suppliers on {
  case (((sale, purchaser), product), supplier) =>
    sale.productId === product.id &&
    sale.purchaserId === purchaser.id &&
    product.supplierId === supplier.id
}

… Превращается в довольно большого монстра с множеством производных таблиц, которые совершенно не нужны, учитывая исходный запрос (форматирование мое):

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
select x2.x3, x4.x5, x2.x6, x2.x7
from (
    select x8.x9 as x10,
           x8.x11 as x12,
           x8.x13 as x14,
           x8.x15 as x7,
           x8.x16 as x17,
           x8.x18 as x3,
           x8.x19 as x20,
           x21.x22 as x23,
           x21.x24 as x25,
           x21.x26 as x6
    from (
        select x27.x28 as x9,
               x27.x29 as x11,
               x27.x30 as x13,
               x27.x31 as x15,
               x32.x33 as x16,
               x32.x34 as x18,
               x32.x35 as x19
        from (
            select x36."id" as x28,
                   x36."purchaser_id" as x29,
                   x36."product_id" as x30,
                   x36."total" as x31
            from "sale" x36
        ) x27
        inner join (
            select x37."id" as x33,
                   x37."name" as x34,
                   x37."address" as x35
        from "purchaser" x37
        ) x32
        on 1=1
    ) x8
    inner join (
        select x38."id" as x22,
               x38."supplier_id" as x24,
               x38."name" as x26
        from "product" x38
    ) x21
    on 1=1
) x2
inner join (
    select x39."id" as x40,
           x39."name" as x5,
           x39."address" as x41
    from "supplier" x39
) x4
on ((x2.x14 = x2.x23)
and (x2.x12 = x2.x17))
and (x2.x25 = x4.x40)
where x2.x7 >= ?

Кристофер Фогт, бывший сопровождающий Slick и все еще активно участвующий в сообществе Slick, объясняет вышеизложенное следующими словами:

Это означает, что Slick полагается на оптимизатор запросов вашей базы данных, чтобы иметь возможность выполнять SQL-запрос, который Slick произвел эффективно. В настоящее время это не всегда так в MySQL

По словам Кристофера, одна из основных идей Slick:

Slick — это не DSL, который позволяет вам создавать точно указанные строки SQL. Перевод запросов Slick в Scala позволяет повторно использовать и компоновать, а также использовать Scala в качестве языка для написания ваших запросов. Он не позволяет вам предсказать точный SQL-запрос, только семантику и приблизительную структуру.

Слик против JOOQ

Поскольку позже Кристофер также сравнил Slick с jOOQ, я позволил себе присоединиться и добавить свои два цента:

С высокого уровня (без реального опыта Slick) я бы сказал, что Slick и jOOQ одинаково хорошо сочетаются с композицией. Я видел сумасшедшие запросы нескольких сотен строк SQL-кода [jOOQ] в клиентском коде, составленном из нескольких методов. Вы можете сделать это с обоими API.

С другой стороны, как сказал Крис: Slick фокусируется на коллекциях Scala, jOOQ — на таблицах SQL.

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

Я предполагаю, что в конечном итоге все сводится к тому, хотите ли вы рассуждать о коллекциях Scala (запросы лучше интегрированы / более идиоматичны с вашим клиентским кодом) или о таблицах SQL (запросы лучше интегрированы / более идиоматичны с вашей базой данных) .

На этом этапе я хотел бы добавить еще два цента к обсуждению. Клиенты не покупают продукт, который вы продаете. Они никогда не делают. В случае Hibernate клиенты и пользователи надеялись навсегда забыть о SQL. Противоположность верна. Как сказал сам Гэвин Кинг (создатель Hibernate):

Gavin-король

Поскольку клиенты и пользователи никогда не слушали Гэвина (и других создателей ORM), у нас теперь есть то, что многие называют несоответствием объектно-реляционного импеданса . Много неоправданной критики было высказано против Hibernate и JPA, API, которые просто слишком популярны из-за ограниченного объема, который они действительно охватывают.

С Slick ( или CQ LINQ, в этом отношении ) аналогичное несоответствие препятствует интеграции, если пользователи злоупотребляют этими инструментами из-за того, что они считают заменой SQL. Slick отлично справляется с моделированием реляционной модели непосредственно на языке Scala. Это замечательно, если вы хотите рассуждать об отношениях так же, как вы рассуждаете о коллекциях. Но это не SQL API. Чтобы показать, насколько сложно преодолеть эти ограничения, вы можете просмотреть систему отслеживания проблем или группу пользователей, чтобы узнать о:

Мы просто назовем это:

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

SQL намного больше

Маркус Винанд (автор популярного объяснения производительности SQL ) недавно опубликовал очень хорошую презентацию о «современном SQL», идею, которую мы полностью поддерживаем на jOOQ:

Мы считаем, что API, которые пытались скрыть язык SQL от языков общего назначения, таких как Java, Scala, C #, упускают множество замечательных функций, которые могут добавить огромную ценность вашему приложению. jOOQ — это API, который полностью охватывает язык SQL со всеми его замечательными функциями (и всеми его особенностями). Вы, очевидно, можете или не можете согласиться с этим.

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

Однако, как небольшой тизер, я хотел бы объявить о последующей статье, показывающей, что не существует такого понятия, как несоответствие объектно-реляционного импеданса. Вы (и ваш ORM) просто неправильно используете SQL. Будьте на связи!