Рубріки: Бази даних

Як перестати ненавидіти і полюбити ORM

Володимир Рожков

Серед багатьох досвічених розробників існує думка, що ORM — це щось погане. Його звинувачують в низькому перформенсі, непотрібних абстракціях та вихованню поганого смаку.

Щоразу коли читаю ті історії, то ніяк не можу второпати, що авторам не подобається, бо я з ORM-ами ніяких проблем не маю.

Історія взаємодії з ORM

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

Згодом я успішно користувався JPA/Hibernate і мав халепу тільки зі специфічними речами типу bigint, який не хотів мапитися чи то через багу Хібера, чи то через особливості MariaDB.

А після ActiveRecord я не дуже уявляю як можна бути продуктивним без ORM. У всіх своїх проєктах SQL мені доводилося писати тільки для запитів пов’язаних зі статистикою.

Відома моя любов до Rails, але ActiveRecord я люблю найбільше, ось, наприклад запит на витягування чергового щоденного збору для @Donate1024Bot

Post.where(state: "approved")
    .where.not(amount: nil)
    .where.not(goal: nil)
    .where(posted_count: 0)
    .where(scheduled_at: Time.now.utc.to_date)
    .order(:id)
    .first

Ефективна робота з ORM

Не буду по пунктах розбивати класичні аргументи проти, натомість напишу що потрібно вам, щоб бути ефективним.

Головне — добре знати та розуміти SQL. Коли ви вже розумієте як зробити потрібний вам запит то не буде жодних проблем з тим щоб конвертувати його в ефективний ORM-код. Мені здається що часто люди скаржаться на код програмістів які почали користуватися ORM без хороших знань SQL і нарубали дров. Таке звісно нікуди не годиться.

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

Всі ORM-и вміють це робити, але, з невідомих причин, це не всюди увімкнено за замовчуванням, наприклад, у Spring/JPA це треба конфігурувати окремо. Одна з величезних переваг ActiveRecord — це такий лог. Наприклад, запит зверху покаже нам ось таке:

Post Load (56.3ms)  SELECT "posts".* FROM "posts" WHERE "posts"."state" = $1 AND "posts"."amount" IS NOT NULL AND "posts"."goal" IS NOT NULL AND "posts"."posted_count" = $2 AND "posts"."scheduled_at" = $3 ORDER BY "posts"."id" ASC LIMIT $4  [["state", "approved"], ["posted_count", 0], ["scheduled_at", "2023-09-18"], ["LIMIT", 1]]

В консолі воно ще й красиво розфарбовано, тут ми можемо бачити: час виконання запиту, сам запит та «бінди», ті параметри які в нього були передані. Цієї інформації більш ніж достатньо для того, щоб писати ефективні запити.

Третє — розуміти що таке N+1 та як у вашому ORM-фреймворку цього уникнути. Здається що N+1 це найрозповсюдженіша проблема з ORM, на що лаються ті самі досвічені програмісти, хоча вона дуже легко виявляється та виправляється. Просто почитайте як у вас робиться includes або FetchMode.EAGER і більше не матимете з тим клопоту.

Гадаю що 95% всіх проблем з ORM зводиться саме до N+1 та нерозуміння, як з ним впоратися.

Четверте — розуміти ціну створення об’єктів та використовувати методи які дозволяють уникнути цього. Наприклад, якщо нам треба взяти з таблиці тільки одне поле, id, то замість ids = User.all.map(&:id) можна використати ids = User.all.pluck(:id) яке не буде створювати об’єкти User, а дістане лише масив id. Rails люб’язно друкує статистику щодо кількості інстанційованих об’єктів в лог, тому там відразу зрозуміло, де це вже впливає на швидкодію.

Люблю ORM, використовую у всіх проєктах, раджу робити те ж і вам.

Практична порада

Увімкнути логи свого ORM та подивитися на запити які він генерує. Подумати що можна покращити та почитати документацію або Tips&Tricks до свого фреймворку.

Цей текст з особистого блогу, опублікований з дозволу автора.

Якщо ви знайшли помилку, будь ласка, виділіть фрагмент тексту та натисніть Ctrl+Enter.

Останні статті

AI Engineer у сучасному технологічному стеку: трансформація процесів розробки програмного забезпечення

Штучний інтелект (ШІ) вже не просто модне слово, а рушійна сила, що змінює саму суть…

21.08.2025

Алгоритми консенсусу майбутнього: DAG, BFT, DPoS

Алгоритм консенсусу – це серце будь-якого блокчейна. Саме він визначає, хто і як записує нові…

12.08.2025

CSR у Next.js. Як працює і що у нього під капотом

Зайшов на сторінку, а там — спінери, skeleton і порожнеча? Це не баг, це —…

31.07.2025

Чому я пишу про факапи?

Таке запитання мені поставив мій знайомий, коли побачив мій профіль. Я настільки над цим задумалась,…

30.07.2025

Як налаштувати штучний інтелект з унікальною базою знань? (безкоштовно)

Нещодавно я вписався в один цікавий проєкт. Довелося розібратись з процесом звітності американських фармацевтичних компаній…

29.07.2025

Одного разу я сильно посварився з СЕО компанії або Коли треба вчасно зупинитися і вміти сказати «ні»

Одного разу я сильно посварився з СЕО компанії. Він кричав на мене, а я у…

28.07.2025