Сучасна диджитал-освіта для дітей — безоплатне заняття в GoITeens ×
Mazda CX 30
×

ORM та заміна бази даних

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті

В контесті статті про хібер давайте ше отаку штуку обговоримо.

Однією з переваг ORM та інших абстракцій над базами часто називають «можливість легко змінити underlying провайдера».

Чи часто вам у ваших проектів була до нагоди ця можливість? Чи було колись таке що вам треба було змінювати базу даних у існуючому проекті?

В мене — ніколи. Зараз є один проект де я серйозно розглядаю можливість переїзду з MariaDB на Postgresql (в основному через інфраструктурні причини та більший вибір DBaaS саме на постгресі. А ще там прикольніший explain) і це єдиний випадок за все життя, причому я ще не почав міграцію а лише сильно замислююсь чи воно мені треба, і чи воно того варте.

А в компанії де я колись працював весь продукт був побудований довкола Oracle і було прийняте стратегічне рішення імплементувати все те саме не постгресі. І це був серйозний проект, на сотню людей та пару років. Щоправда я там участі не брав, тому воно не рахується.

Сюди ж питання про доцільність «прибивання» цвяхами бази до об’єктів (user.save замість usersRepo.save(user)).

👍ПодобаєтьсяСподобалось0
До обраногоВ обраному0
LinkedIn

Найкращі коментарі пропустити

Чи було колись таке що вам треба було змінювати базу даних у існуючому проекті?

— постоянно этим занимаюсь, только мне попадаются кейсы поинтересней (Access — Cache(MUMPS), MySQL — Mongo, DynamoDB — Neptune).

«можливість легко змінити undelying провайдера».

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

И поймите процесс миграции может быть длительным (дни — месяцы) поэтому вначале вам надо подготовить инфраструктуру в новой СУБД — настроить процесс импорта данных с одной СУБД в другую (хорошо если можно обойтись просто ODBC) но возможно придется ещё что-то делать.

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

Большинство работы придется делать в любом случае «ручками» — ибо не существует автоматических механизмов и инструментов способных мигрировать произвольную структуру БД1 на СУБД1 — в произвольную (пусть и очень похожую) структуру БД2 на СУБД2 — и что самое обидное — эта работа будет одноразовой (то есть после того как весь процесс пройдет — вы этот код не будете использовать) но требования к нему самые высокие. Помимо этого вы должны четко определить область данных которая является критически (финансово ценной) и не может быть утеряна или рассогласована в том или ином виде. да да — при миграции данных всегда будут потери (единичные несущественные записи) но вы должны это понимать и критические данные проверять совсем другими видами тестов. Кстати если есть справочная медленно меняющаяся информация — её конечно надо мигрировать в первую очередь. Вобще правило следующее — чем медленней меняются данные — тем в первую очередь их мигрируете (но настраиваете процессы синхронизации для них все равно) просто в процессе миграции основных данных — даже справочники могут измениться.

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

Но все меняется в принципе если вы можете остановить проект на сутки (предположим) промигрировать все и выехать на новых рельсах (не меняя структуры таблиц индексов полей и названий). Но это просто как переехать на новую версию старой СУБД (практически) да проверить все ендпоинты (грубое упрощение).

Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Oracle -> postgres несколько раз. Без всяких ORMов относительно легко перевелось, благо концептуально близки со стороны клиента. Алгоритм был обычно: обложили интеграционными тестами с докеризированной базой ORA, вынесли всю логику и триггеры из базы в код приложения, добавили поддержку PG (пару отличий параметризируются JDBC url), добавили в билд докеризированный PG с теми же тестами, готовы к миграции. Дальше или даунтайм с копированием данных или теневой запуск, синхронизация данных например Кафкой, отключаем ORA.

Пару раз выбрасывал Хибернейт, после чего в релиз OPSы прибегали роллбекать требовали — слишком малая нагрузка на базу. Один раз таки пришлось роллбечить, так как заработало слишком быстро.

Какие такие механизмы нагрузки базу встроены в нем?

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

100%. Но базу в любом случае понимать нужно в нетрививальных приложениях — от этого никуда не деться. А Хибернейт — это дополнительный уровень, и непростой. Если можно избежать — хорошо.

Чему схлопывание Скалы хорошая иллюстрация.

Тоже интересовал этот вопрос. Может голосовалку прикрутите, чтоб по итогу была статистика ?

Чи було колись таке що вам треба було змінювати базу даних у існуючому проекті?

— постоянно этим занимаюсь, только мне попадаются кейсы поинтересней (Access — Cache(MUMPS), MySQL — Mongo, DynamoDB — Neptune).

«можливість легко змінити undelying провайдера».

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

И поймите процесс миграции может быть длительным (дни — месяцы) поэтому вначале вам надо подготовить инфраструктуру в новой СУБД — настроить процесс импорта данных с одной СУБД в другую (хорошо если можно обойтись просто ODBC) но возможно придется ещё что-то делать.

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

Большинство работы придется делать в любом случае «ручками» — ибо не существует автоматических механизмов и инструментов способных мигрировать произвольную структуру БД1 на СУБД1 — в произвольную (пусть и очень похожую) структуру БД2 на СУБД2 — и что самое обидное — эта работа будет одноразовой (то есть после того как весь процесс пройдет — вы этот код не будете использовать) но требования к нему самые высокие. Помимо этого вы должны четко определить область данных которая является критически (финансово ценной) и не может быть утеряна или рассогласована в том или ином виде. да да — при миграции данных всегда будут потери (единичные несущественные записи) но вы должны это понимать и критические данные проверять совсем другими видами тестов. Кстати если есть справочная медленно меняющаяся информация — её конечно надо мигрировать в первую очередь. Вобще правило следующее — чем медленней меняются данные — тем в первую очередь их мигрируете (но настраиваете процессы синхронизации для них все равно) просто в процессе миграции основных данных — даже справочники могут измениться.

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

Но все меняется в принципе если вы можете остановить проект на сутки (предположим) промигрировать все и выехать на новых рельсах (не меняя структуры таблиц индексов полей и названий). Но это просто как переехать на новую версию старой СУБД (практически) да проверить все ендпоинты (грубое упрощение).

Прям переехать — нет, назревает, но там так просто не обойдется
Был энтерпрайз проект с поддержкой MS SQL и Oracle, но там и подобие ORM было самописное неизвестными динозаврами

Чи часто вам у ваших проектів була до нагоди ця можливість? Чи було колись таке що вам треба було змінювати базу даних у існуючому проекті?

На 2х разных проектах приходилось использовать 2 различные БД. 2 раза возникала проблема, связанная с native quieries — использовали различные специфические фишки разных БД. Разруливалась эта проблема 2мя способами:
1. через spring active profiles
2. через переписывание на JPQL с перфомансным тестированием и ассертами на сгенеренные query

В остальном, базовый CRUD работал нормально.

Однією з переваг ORM та інших абстракцій над базами часто називають «можливість легко змінити undelying провайдера».

Чи часто вам у ваших проектів була до нагоди ця можливість? Чи було колись таке що вам треба було змінювати базу даних у існуючому проекті?

Не надо было ни разу. Кроме того, считаю возможность поменять СУБД недостатком, а не преимуществом. Например в Postgres есть window functions (можно например посчитать накопительную сумму для какого-нибудь столбца в таблице, и это самое простое), а в MySQL такого нет. Если писать в расчете на переключение СУБД одной строкой в конфиге, теряешь практически все преимущества конкретной СУБД.

в MySQL такого нет

Вже є.

І я не зовсім зрозумів, що значить «посчитать накопительную сумму» — можливо, це те, що давно існувало, як ’WITH ROLLUP’?

Ну хорошо что уже есть. Когда мне нужно было решать такую задачу — не было. Накопительная сумма для каждой строки в результате запроса. Например есть таблица с продажами (дата, сумма) и нужно нарисовать график, показывающий как менялась общая прибыль со временем — sum(amount) over(order by timestamp)

Ну и я не слышал об орм, которая в-принципе подобные задачи покрывает

как менялась общая прибыль со временем

А, в цьому смислі. Так ця задача тривіально вирішується і без віконних функцій.

SELECT sale_date
     , sale_sum
     , @running_sum := @running_sum + sale_sum AS rsum
  FROM sales 
 WHERE sale_point_id = 12345
   AND (( @running_sum := 0 ) OR 1 )
 ORDER BY sale_date ASC

Интересный прием с AND (( @running_sum := 0 ) OR 1 ). Я почему-то думал что без SET @running_sum := 0; данный способ не работает.

А якщо потрібна running_sum з рестартом на початку місяця чи з додатковим групуванням по sale_branch?

Теж можна :) Оце для випадку, коли в нас строго одна sale_sum в день.

SELECT sale_date
     , sale_sum
     , IF( DAYOFMONTH(sale_date) = 1
         , @running_sum := sale_sum 
         , @running_sum := @running_sum + sale_sum 
         ) AS rsum
  FROM sales 
 WHERE sale_point_id = 12345
   AND (( @running_sum := 0 ) OR 1 )
 ORDER BY sale_date ASC
Якщо може бути декілька продажів за день, або окремо по бранчах — теж без проблем, але доведеться ще одну змінну вводить.

ага, ідея в цілому ясна.
а якщо треба суму рестартувати по якійсь групі з по 4 колонок, то буде 4 змінних і 4 (чи більше?) вкладених IF?
з віконною функцією нмд якось зрозуміліше буде виглядати.

Можна просто конкат використовувать для значень тих 4 колонок. Фішка в зміні значення UDV.

Віконні ф-ції — це добре, але до 8 версії мускля та 10.2 маріїдб їх не було, тому в старих базах доводиться викручуватися.

Оце для бранчів:

SELECT branch
     , sale_date
     , sale_sum
     , IF( @cur_branch <> (@cur_branch := branch)
         , @running_sum := sale_sum 
         , @running_sum := @running_sum + sale_sum 
         ) AS rsum
  FROM sales 
 WHERE sale_point_id = 12345
   AND (( @running_sum := 0 ) OR 1 )
   AND (( @cur_branch := 0 ) OR 1 )
 ORDER BY sale_date ASC
Якщо треба групувать по 4 колонках, то досить використати
IF( @udv <> (@udv := concat(col1, col2, col3, col4))

Забув в ордері по бранчу-даті відсортувати.

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

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

SQL з цим впорається просто на відмінно.

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

Але це треба знати самі СУБД :)

Ти кидаєш інсерт — а воно тобі фак з описом трабли.

Типа проканает не проканает? Это куйня а не валидация, валидация на уровне бизнесслогики должна обьяснить пользователю что конкретно не так.
И можно даже коннекшен в базу не открывать и показать эррор меседж пользователю. Или ты предлагаешь ему самому запросы писать?
Описание траблы Какой ? sorry but the foreign key is already exist?Или ты предлагаешь локализированному приложению тексты для UI хранить в базе?
Обработка эксепшенов на разных слоях приложения это отдельная тема, ошибки из базы не должны быть видны пользователю, он вообще о них не должен знать.
Можно и троллейбус из буханки, но зачем? Просто потому что можно?
Сиквел отлично справляется с агрегацией данных, вот пусть ими и занимается.

Объясни задачу людскими словами. Если это sum — то как бы агрегат «из коробки» и «group by» никто не отменял. Решается это разумеется на базе данных, просто потому что агрегация данных да и вообще аналитика — РОВНО НИКАК не работают на фреймворках абстракции. Фреймворки нужны для абсолютно других вещей, не связанных с админ-полномочиями и управленческими функциями. Точно так же как ты не лезешь делать разбивку диска с которого у тебя работает операционка.

Задача фреймворка — решить типичные задачи. Для не-типичных первым делом что ты сделаешь — инвалидация кеша, если лезешь менять данные массово.

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

Задачи с аналитикой решаются так: на уровне отдельного приложения выполняется:
— сброс кешей [выборочно] если требуются свежие данные, ИЛИ отдельной процедурой данные за текущий период анализируются отдельно [если это highload]. В большинстве случаев свежие данные «сегодня за сегодня» аналитику не нужны.
— собирается ОТДЕЛЬНАЯ статистическая таблица по конкретным аргументам, и она ХРАНИТСЯ некоторый период.
— существует ОТДЕЛЬНАЯ процедура ночного обслуживания базы, которая вычищает старый собранный аналитический мусор.
— похожая процедура есть для чистки этих кешированных данных, в случае если за какие-то даты исходные данные поменялись. В немалой доле проектов это запрещено и не предусмотрено, и в случае редчайших ручных правок попросту чистят весь кеш.
— очень часто в нагруженных мелкой аналитикой проектах есть ДВЕ копии таблиц с накопленной статистикой, одна со свежими данными и недавно собранными агрегатами [срок годности которым от минуты до часа], одна с данными за прошедшие периоды, к которым редко обращаются, и тем более правят. Выгода — снижение риска порчи данных, снижение расходов на переиндексацию, снижение цены вставки и удаления данных.

И всё это НЕ КАСАЕТСЯ фреймворка. Разве что существует поток обслуживания, который принудительно сливает данные из кешей, чтобы статистика не запаздывала.

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

Объясни задачу людскими словами.

Я уже объяснил и Артем Перекресний понял о чем я. На английском такую задачу называют "running total"/"cumulative sum"

Задачи с аналитикой решаются так

Так они решаются только когда у тебя это аналитика в админке для работников и строится по херовой туче данных. Когда продаешь SAAS для анализа данных (внесенных пользователем) — таки нужно строить графики и таблички по запросу пользователя (+ с фильтрами).

Я собственно не против ORM для простого CRUD, но что-то ни разу простого CRUD не видел. Обязательно нужно сделать что-то более сложное чем 4 базовые операции.

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

Насчёт running total — я не совсем понимаю его применение в SELECT. Если это нужно считать часто — посчитал бы уже в приложении, один хер набор данных это не уменьшит. Другими словами, это целиком ложится во фреймворк. И очень даже может быть, что накопительный итог может быть отрисован фреймворком построения самого графика. А даже если нет — совсем маленький скрипт на стороне клиента всё сделает сам, SQL ему для этого не нужен совсем. Выгода — в читаемости кода.

Положить/забрать сущность в базу, возможно забрать еще связанные сущности. Что-то ещё забыл?

У джавистов спросите, я на JS пишу

Оконные функции есть в одном из последних стандартов ANSI SQL, поэтому есть или будут во всех популярных базах

они давно есть в майкрософте и оракле (около 10 лет) — но запросы пишутся по разному

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

ограничивает разработчиков в возможностях, которые предоставляет та или иная СУБД

Не просто обмежує, а зводить використання РСУБД до такої мізерної спільної підмножини функціоналу, що вся затія починає ілюструвати ідіому «з гармати по горобцях».

Нема що обговорювати. Якщо це абстракція, вона втрачає всі переваги, які може надати база даних. Плюс базу даних доводиться попускати, вимикаючи все зайве. Тому переваг нема жодних. І тільки коли проект вже набрав масштаби переходу на Kubernetes можеш паритись за базу.

Я бачив кілька разів, коли в самих розробників стоїть одна база, а на продакшені інша. Як не дивно, тести навіть не нявкнули.

Є відмінності на скриптах обслуговування, які виконуються на самій базі. Можуть бути відмінності на процедурах, особливо якщо база є генератором ідентифікаторів.

Коментар порушує правила спільноти і видалений модераторами.

Ровно до тех пор, пока тебе не дали толковые задачи

Хорошая задачка на собеседование:
найти подстроку

тормозное говно

в строке

Ruby on Rails Team Leader

:)

На собеседования рубисты приходят с вазелином и без нижнего белья ©

осталось только достать их из экскаватора

обосрать ActiveRecord

От я пройшов трійко собєсів, ні разу такого не було.

А чим він поганий? ActiveRecord? Мені от все дуже подобається, я прям тащуся. Для складних черей пишу ActiveRecord::Base.connection.execute і тд.

но по моему опыту есть часть народу, которая молится на ORM и пихает ее куда надо и куда не надо

Тренд «построить из готовых компонентов» очень плохо влияет на индустрию, особенно на начинающих разработчиков. Заглядываю иногда на SO в тег emberjs и создается впечатление что многие документацию к фреймворку дальше чем npm install/ember install не читают. Всё программирование у них сводится к нагуглить плагин, поставить, пойти спрашивать на SO почему не работает. Соответственно на бекенде такие тоже используют только готовое и впадают в ступор если «готовое» там не хочет работать с «готовым» на фронте.

А можно использовать вслепую и наплодить кучу n+1 запросов.

Так это проблема психологии, а не технологии.
Документация доступна, вроде все там написано. Но сказать — я неправ, не понял для чего нужен includes и вообще не читал документацию и знаю очень мало, очень тяжко.
Проще обложить фекалиями тех, кто не может ответить (то есть соот. разработчиков соот. инструмента)

Документация хорошо отвечает на вопросы «как сделать», но ничего не говорит о том «что делать» и (что важнее) «чего не делать». В итоге без дополнительных целенаправленных усилий AR в проекте стимулирует появление чудовищных god models с кучей костылей типа условных валидаций, коллбеков и вот этого всего. Вся эта логика еще и неизбежно протекает в 100500 разных мест, в итоге имеем чудовищное неподдерживаемое говно. Конечно же это не проблема AR как такового, но факт что он косвенно стимулирует не очень здоровые решения, предоставляя из коробки инструменты, которыми в общем-то в большинстве случаев лучше бы не пользоваться вообще. С другой стороны, молотком тоже можно по пальцам, но никто после этого не говорит, что молотки — зло в принципе...

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

А плейн jdbc не адок?

большинство select-ов таки переписывается, все это добро запихивается в кеш

Напрашивается вывод — CQRS наше всё? :) В Command части, где данные записываются в базу, использовать ORM очень удобно, так как зачастую вовлечена нетривиальная бизнес-логика, реализовывать которую, всё же, удобнее в терминах бизнес-сущностей и операций над ними.

Мимо ORM здесь имеет смысл ходить только в особых случаях наподобие bulk import, в которых от ORM никакой пользы всё равно не будет ввиду отсутствия бизнес-логики. А если требуется импорт с некоей логикой трансформации — так, опять же, для этого есть совсем другие инструменты из серии ETL.

А вот в Read части со сложными запросами, где требуются оптимизация и тюнинг — ORM не нужен по определению, и здесь рулят и бибикают гораздо более тонкие прослойки между логикой отображения и базой данных: Dapper, JdbcTemplate и т.п. Вот, правда, какие аналоги этому есть в Ruby — я, к сожалению, не в курсе.

хоча це не відноситься до ORM. Але у випадку наявності великої кількості логіки на рівні СУБД, виникає дуже багато моментів щодо міграції. Та таких проектів дуже мало :)

А в чому проблема переписати процедури-трігери-в’юшки на іншому діалекті SQL, якщо вже постало питання міграції? Все одно запити доведеться переписувать, або в базі, або в клієнтському софті.

Взагалі то ніколи ні в чому немає проблеми. Просто час і просто гроші

Ну так от я і намагаюся з’ясувати, чому переписування логіки на боці СУБД вимагає більше часу та грошей, порівняно з переписуванням коду на боці клієнтського софта? Я так зрозумів, що при міграції перше створює «моменти», а друге — ні. Хотілось би зрозуміти, чому.

Можливості у реалізації хоча б тих же процедур у кожної свої і зі своєю специфікою. І не завжди вдавалося перенести один в один з однієї СУБД на іншу. У моєму випадку було з MS SQL Server на PostgreSQL. І там були не якісь прості або проміжні запити, а функціонал, який виконувався годинами з метою формування звітності

Тобто, якби весь той самий функціонал був би реалізований на боці клієнтської аплікухи, то ніяких складностей не виникло б?

Я просто хочу зрозуміти, чому логіка на боці СУБД вважається злом :)

Я нічого не сказав про зло. Просто ускладнюється перенос.
Одне діло правити код для проектів на інтерпретаторах, а інше діло, коли проект компілюється. Логіка на стороні СУБД по суті є хорошим варіантом (за можливості) у випадках, коли проект компілюється.

Я просто хочу зрозуміти, чому логіка на боці СУБД вважається злом :)

В субд гораздо менее выразительный код. При разрастании этой логики на стороне субд получается каша, в которой чтото понимает только автор(ы).

Оце новина :) В субд, SQL яких заточених на роботу з даними, код менш виразний ніж те саме, але у вигляді велосипеду на жабі??

Все набагато простіше: SQL та бази — це інша, неімперативна парадигма, в яку пересічний програміст в’їжджає дуже важко, а частіше — зовсім не в’їжджає. І тому пише «виразний код» на тому, що знає, і байдуже, що при цьому майже гарантовано втрачається як ACID-ність даних, так і продуктивність БД в цілому.

Ой, у нас тут адепты написания ентерпрайз приложений внутри базы на пл-скл.
Ну успехов, чо :)

давайте успешные enterprise примеры, где все сделано та клиенте и ваше там участие.

А хто каже, що всю логіку треба в БД пхать? В БД треба пхать тільки ту логіку, що ефективно та прозоро лягає на дані. Ну, і робить API-like набір процедур, щоб в базу не лізли немитими руками.

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

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

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

да, но это даже не звериный оскал коммандной строки

Про управляемость очень хочу послушать. В самом начале 2000х я участвовал в проекте, где часть бизнес-логики, причём — далеко не тривиальной — была реализована в хранимых процедурах. Поддерживать всё это добро в работоспособном состоянии мог только один DBA (привет bus factor).

Никакому автоматизированному тестированию эта логика, естественно, не поддавалась, в результате чего DBA львиную часть времени был занят багофиксами этой логики.

Да и с контролем версий для исходников этих хранимок были постоянные грабли (отчасти можно списать на незрелость инструментария тех лохматых годов — с ужасом вспоминаю Visual InterDev — но, всё же...)

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

Никакому автоматизированному тестированию эта логика, естественно, не поддавалась

есть tSQLt фреймворк например

DBA львиную часть времени был занят багофиксами этой логики.

Это был скорее Дб Девелопер

Поддерживать всё это добро в работоспособном состоянии мог только один DBA (привет bus factor).

тут зависит от конкретной реальзации. Самое худшее что видел — в базе 160 триггеров с бизнес логикой и местами GOTO в коде.

С процедурами все ок и это лучшее что у вас может быть с точки зрения производительности базы

Мне сложно придумать сценарий, когда разница в производительности вставки / изменения данных между использованием ОРМ и хранимки будет столь существенной с точки зрения бизнеса. Наверное, только в случае, если для реализации бизнес-логики нужно делать запросы больших объёмов данных и гонять их с DB сервера на application server — и то, вероятно, можно выкрутиться write-through кэшированием.

А для вычитки данных ИМХО тогда уже логичнее использовать view / materialized view.

конечно же важен размер базы и что именно вы с ней делаете

А для вычитки данных ИМХО тогда уже логичнее использовать view / materialized view.

поможет с конкретно одним селектом, но это не цель.
при хорошо продуманном дизайне должно хватить индексов и джоинов

Pros and Cons
Using ORM saves a lot of time because:

DRY: You write your data model in only one place, and it’s easier to update, maintain, and reuse the code.
A lot of stuff is done automatically, from database handling to I18N.
It forces you to write MVC code, which, in the end, makes your code a little cleaner.
You don’t have to write poorly-formed SQL (most Web programmers really suck at it, because SQL is treated like a “sub” language, when in reality it’s a very powerful and complex one).
Sanitizing; using prepared statements or transactions are as easy as calling a method.
Using an ORM library is more flexible because:

It fits in your natural way of coding (it’s your language!).
It abstracts the DB system, so you can change it whenever you want.
The model is weakly bound to the rest of the application, so you can change it or use it anywhere else.
It lets you use OOP goodness like data inheritance without a headache.
But ORM can be a pain:

You have to learn it, and ORM libraries are not lightweight tools;
You have to set it up. Same problem.
Performance is OK for usual queries, but a SQL master will always do better with his own SQL for big projects.
It abstracts the DB. While it’s OK if you know what’s happening behind the scene, it’s a trap for new programmers that can write very greedy statements, like a heavy hit in a for loop.

при хорошо продуманном дизайне должно хватить индексов и джоинов

Для произвольных запросов — да. Причём, может оказаться так, что эти запросы лучше перенаправлять на отдельную read-only реплику, чтобы не упираться в disk I/O throughput.

опять же зависит от дизайна базы размера и запросов. плюс сколько памяти и какая часть таблиц будем в bufer poоl закешированна и как долго.
просто отселять запрос делающий фулскан таблицы на отдельную реплику без его оптимизации смысла нет.
а вот если на primary реплике очень интенсивная запись в базу, то возможно и есть смысл

если на primary реплике очень интенсивная запись в базу, то возможно и есть смысл

Да, я именно об этом сценарии

выкрутиться write-through кэшированием.

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

возможно в конкретно вашем случае вам вобще не нужна релационная база а хватит Редиса какого-нибуть

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

пули вылетели, проблемы не у нас

Этот сарказм, если честно, не очень понял. Конечно, есть вероятность криво реализовать кэш, но мы же, вроде, не об этом?

если делать самописный кеш надо подумать чт будет с данными которые еще не записались в базу в случае растарта сервера и т.д.
а так да, можно.
Но опять же БД в вашем случае такой себе склад, но база полноценно не используется
dou.ua/...​ign=reply-comment#1582894

But ORM can be a pain:

You have to learn it, and ORM libraries are not lightweight tools;
You have to set it up. Same problem.
Performance is OK for usual queries, but a SQL master will always do better with his own SQL for big projects.
It abstracts the DB. While it’s OK if you know what’s happening behind the scene, it’s a trap for new programmers that can write very greedy statements, like a heavy hit in a for loop.

релігія яких ООП

Я могу допустить, что ООП религия. Пусть люди с другой религией пишут другой код. Возможно, он лучше или просто хорош. Но

TDD

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

хранімка зазвичай виглядає як простирадло

так може треба почати з основ структурного програмування?
а то всі зразу в «класи» і «патерни» лізуть, а розбити функції на менші кусочки не можуть

Я просто хочу зрозуміти, чому логіка на боці СУБД вважається злом :)

В тому що в тебе тепер два місця де можуть змінюватися дані, і одне місце не завжди може знати про інше.

В сучасному світі, де софт пишеться не в одиночку, це твердження справедливе навіть в межах одного фрагменту системи. Два фронтендщика можуть абсолютно не знати/розуміти, що і як робить їхній колега.

Два фронтендщика можуть абсолютно не знати/розуміти, що і як робить їхній колега.

Вони можуть не знати що робить їх колега, але вони обидва знають що для роботи зі стейтом треба використовувати який-небудь redux/mobx.

для роботи зі стейтом треба

Не обов’язково.

Не обов’язково.

Т.е. вы сознательно защищаете худшие практики?

Я натякаю, що сьогодняшні «кращі практики» завтра проклянуть та піддадуть анафемі.

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

де софт пишеться не в одиночку, це твердження справедливе навіть в межах

Где тим/техлид ложил болт, там да, не обязательно. А вообще обязательно.
Вот вы думаете что необязательно, а потом боинги падают.

1. Дебаг процедур як правило істотно складніший.
2. Перехід на іншу бд болісний. Процедури треба буде писати з нуля . А клієнтський код написаний на орм просто запрацює.
3. Деплоймент складніший.
Є проекти які можуть продаватись багатьом замовникам. А є корпорації які на рівні корпоративної етики не будуть використовувати щось опенсорсне чи безплатне. В декого куплені прикольні бази.

1. Згідний. Але не тому, що це процедури, а тому, що ефективність процедур вимагає акуратного побудування моделі даних. Якщо РСУБД використовувать в якості примітивного стораджа «ключ-значення», то логіка процедур неминуче ускладнюється.

2. ОРМ-код просто працює, «якщо РСУБД використовувать в якості примітивного стораджа «ключ-значення». При цьому неминуче страждає продуктивність системи в цілому. Там, де процедура за 10мс випльовує одну строчку з результатом, через ОРМ доведеться викачать декілька мегабайт даних, які ще потім треба обробить своїми силами, за допомогою не самого підходящого інструментарію.

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

Там, де процедура за 10мс випльовує одну строчку з результатом, через ОРМ доведеться викачать декілька мегабайт даних, які ще потім треба обробить своїми силами, за допомогою не самого підходящого інструментарію.

Что мне нравится в этом холиваре (как и в любом другом баттле технологий/подходов/...), так это натягивание совы на глобус в попытке досвести конкурирующую идею до абсурда :) Зачем качать через ORM все, если нужна одна строка? В таком случае это не проблема маппера, это проблема кривых рук того кто его использует.

А звідки візьметься одна строчка, якщо логіки на боці СУБД нема?

якщо логіки на боці СУБД нема?

сферичний кінь надсилає нам усім поштову картку з Вакууму та посміхається.

CriteriaQuery? И тащите себе спокойно одну строку. Или даже через магию имён методов getBy_тоиэто

Все одно це покриває не більше 1% можливостей РСУБД. Краще вже юзать key-value та не паритись.

Универсального решения нет, везде надо думать и принимать оптимальные решения, если бы можно было — вкл\выкл и не париться, то не было б таких зарплат и спроса на программистов.
А пока — все эти пробелемы — наш хлеб. С маслом :-)

С чего бы? С критерия делал весьма развесистые запросы с джоинами чтобы выдрать ровно то, что надо и запросом таким, как мне надо

Почему-то большинство орм-хейтеров забывают (или не знают), что орм, это блин, всеголишь маппинг резалтсета в объект, и позволяет хоть вообще нейтив квери на диалекте конкретной базы хреначить, при этом имея все плюсы от какогонибудь @SqlResultSetMapping.

Почему-то в понимании орм-хейтеров использование орм это всегда
orm.getAll(GodObject.class);

Почему-то в понимании орм-хейтеров использование орм это всегда
orm.getAll(GodObject.class);

Ну да...
Я, например, сначала «по старинке» пишу обычный SQL запрос, отлаживаю его, чтобы брал из БД только то, что нужно в данный момент и лишь после тестирования и понимания, что все будет Ок — переписываю его в ORM стиле, чтобы результат получить в виде объекта. Почти всегда получается.

Так не проще ли маппер свой собственный написать и вообще не возиться со сторонним ORM при таком подходе? Вы получается сначала тратите время на составление правильного запроса руками, а потом на придумывание как заставить ORM сгенерировать такой же.

Так не проще ли маппер свой собственный написать

Не думал об этом....
Сама не ORM не плохая, вряд ли у меня получится лучше. Время затрачивается, это да, но результат получается достаточно приемлимый за счёт проработки SQL и хорошая совместимость с Фреймворком после рефакторинга в ORM.

А причём тут орм? Что с ним, что без него придётся качать. Если надо скипнуть какие-то поля и/или дочерние ентити, чтобы не тащить лишнего — это вполне работает и с орм.

Відповідь неправильна. У випадку процедури мені вернеться одна строчка з результатом. Без процедури — ну, да, доведеться викачувать всі дані, хоча дехто тут щосили намагався це заперечувати.

А, ну если у вас разговор про хранимки против орм пошел, то я пас. Хотя тоже можно совмещать при желании.

Він саме про це був ізпочатку. Я просто не говорив слова «хранимі процедури» явно, а говорив про логіку на боці БД, яку тут всі рішуче почали гнобить, як абсолютно неприйнятний паттерн.

То що, виявляється, таки прийнятний?

я в религию не очень, сорри

орм хейтеры они такие да

Причем в каждой теме ОРМ заходит какой то хейтер ОРМ

Возможно различия в Субд довольно существенные. В mysql я легко обхожусь без ХП

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

Будь яку пропозицію, що водночас дозволить НЕ тримати логіку на БД, і НЕ качати дані для обробки на стороні клієнта, я вислухаю з щирим непідробним інтересом.

На любой вопрос любой ответ

Що за маячню я читаю?

Ну, звісно, що в різних предметних областях з базами працюють по різному. Для когось це просто занадто ускладнене ключ-значення + простенькі джойни, і цілком вільно можна ту всю ботву загорнути в ОРМ. А для когось це таки реляційна БД, з аналітикою, вітринами і тому подібним мотлохом, для обробки якого довелось би кожен раз ганять дані з БД в клієнта для обрахунку.

У вас складнощі з розумінням прочитаного? Перечитайте мій комент ще раз.

А для когось це таки реляційна БД, з аналітикою, вітринами і тому подібним мотлохом, для обробки якого довелось би кожен раз ганять дані з БД в клієнта для обрахунку.

Так эти задачи через ОРМ ни один вменяемый разработчик решать и не будет. Если правильно понял написанное, оно очень близко к OLAP workload, а ORM — они для OLTP.

Та не про те мова :) Мова про те, що є неперервний спектр моделей використання РСУБД — умовно кажучи, від ТР до АР, і всі вони прийнятні та виправдані, якщо розв’язують поставлену задачу. Але в певних колах поширена думка, що весь АР-функціонал БД — це антипатерн та екзистенціальне зло. Я, власне, і намагався підвести співбесідників до думки, що кейси бувають різні, і те, що для одних неприйнятне, для інших — єдине можливий варіант.

Але в певних колах поширена думка, що весь АР-функціонал БД — це антипатерн та екзистенціальне зло

Ну здесь бы уточнить, о каких именно БД речь... некоторые БД умеют эффективно хранить данные для таких задач, но сами по себе богатых функций аналитики не предоставляют, и эту аналитику приходится наворачивать сверху каким-нибудь Presto / Impala / Spark SQL / Hive.

Если же речь о традиционных реляционных БД с накоплением данных в какой-нибудь star / snowflake schema — ну-у... я лично не встречался с тем, чтобы кто-то считал антипаттерном сложные аналитические запросы к такому хранилищу. Возможно, мне просто повезло :)

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

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

Та я, якраз, в курсі :) Мене тішить ситуація, коли піполь знає лише про вузьку полосу спектра застосування БД. А ще більше мене тішить, коли стверджують, що весь функціонал зверх CRUD — це шкідливо, неефективно і антипатерн :)

Вот, отлично! Вы гораздо более детально расписали мысль, которая крутилась и в моей голове. ORM — для OLTP. Для аналитики и обработки больших данных они изначально не предназначены, и даже странно, что кто-то пытается применить ORM в подобных задачах.

чому логіка на боці СУБД вважається злом

В первую очередь сложностью отладки и поддержки. Особенно когда отлаживать и поддерживать нужно не тому, кто в оригинале это писал

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

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

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

А при этом всем менеджер прочел хайповый заголовок «Админка за 3 минуты с <libraryName>» и не понимает чего девелоперы так долго возятся.

Чи часто вам у ваших проектів була до нагоди ця можливість? Чи було колись таке що вам треба було змінювати базу даних у існуючому проекті?

Писав простий парсер для інтернет-магазину, Symfony Console + DomCrawler + Doctrine, з початку зберігав в MySQL, але потім для взаємодії з 1С замінив на PostgreSQL, пройшло гладко

Розробляв локально API з MySQL без ORM, і щоб протестити API на Android вибрали безкоштовний хостинг, який підтримував тільки PostgreSQL, були написані тести, обновили запити на стиль PostgreSQL і теж пройшло гладко

Можна якісь кількісні-якісні показники БД? Скільки таблиць, в’юшок, скільки зовнішніх ключів, який максимальний рівень джойнів, скільки тригерів та процедур?

Якщо використовувати тільки загальну спільну підмножину можливостей РСУБД, то мігрувати можна з чого завгодно на що завгодно — просто копіпастою.

Можна якісь кількісні-якісні показники БД? Скільки таблиць, в’юшок, скільки зовнішніх ключів, який максимальний рівень джойнів, скільки тригерів та процедур?

В обох проектах до 10 таблиць, жодних процедур та тригерів, JOIN ~ 3

Може не по темі, але я бачив ваші коменти під статтею, тому ось: gorm.grails.org

Однією з переваг ORM та інших абстракцій над базами часто називають «можливість легко змінити undelying провайдера».

Полный булшит от создателей ООП. Это абсолютно нереально сделать в приложении сложнее чем тудулист. Более того, любой проект написанный полностью на орм обречен на смерть от респонзов по 5 минут. Адекватно орм покрывает до 30% работы с базой. Все остальное рав сиквел.

Более того, любой проект написанный полностью на орм обречен на смерть от респонзов по 5 минут.

Не поняв, чому? В мене є проект на хібернейті, все ок. Не хайлоад, але і не сайт-візитка. На базу не скаржусь.

Не поняв, чому?

Потому что «Хибернейт тормозит» — это аксиома для многих.
По моему опыту: 5 минут — это где-то 2-4 пачки по 5-10К объектов для инсерта/апдейта. Пачки по 3К занимают где-то 1-2 минуты.

Я в таких случаях переводил на балкаплоад и хранимки.

На таких об’ємах все що завгодно крім спеціально написаних штук буде «гальмувати».

Тому власне і з ORM з’їжджають на такі маппери як Dapper.

akka streams+ alpakka не будет, если перевести все в стримы.

Стримы как-то ускорят вставку 10K insert/update? Не 5 минут, а 5 секунд?

у меня нормально инсертилось ~6к/с в mysql, (+ постройка индекса, batch-insert), с помощью jdbcTemplate, а orm не просто слоупочило, а ещё и память выедало. А сам по себе React не даст скорости, если все уперлось в базу

Там без ORM по этому побыстрее будет всяко. Если проблема с единичными дёрганиями, то акка поможет её решить. И 10К инсёрта и 10к апдейта бывают разными. Если писать в базу надо, то стримы самое то, если один апдейт, который переписывает пол базы — ничем тут не помочь.

Ну так без ORM, оно и без Akka будет быстрее)

А вообще, на ассемблере всяко будет быстре чем на этих ваших джвмах. Акка не только про sql, она вообще про реактивное программирование, и конкарренси. В большой части случаев там можно получить throughtput побольше и хорошее ограничение по памяти. Мне удавалось запускать одну штуку на 128 мб, и она работала, с гц, конечно. Там была и работа с базой, и походы в сервисы, и дробление чисел немного. Не реактивная реализация на первом запросе бы слегла бы по ООМ. Я сомневаюсь что на голых потоках RX либе можно будет гибко тьюнить параметры и делать ограничение по памяти и настолько хорошую параллелизацию.

«можливість легко змінити undelying провайдера».

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

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

Підписатись на коментарі