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

Як перестати ненавидіти і полюбити 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.

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

Чому написання ідеального коду може призвести до вашого звільнення

Блогер та розробник Джозеф Круз розповів, чому не варто писати ідеальний код та чому це…

18.04.2025

ChatGPT, моторошна долина та трохи Фройда

Днями я завзято нила про щось ChatGPT (експериментую між сеансами з живим терапевтом). І от…

17.04.2025

Я прийшла за покупками, а не крутити колесо

«Крутіть колесо, щоб отримати знижку до 50%!» «Натисніть тут, щоб відкрити таємничу пропозицію!» «Зареєструйтесь зараз,…

16.04.2025

Майже навайбкодив десктопний монітор CI пайплайнів

Дуже хочеться робити якісь десктопні апки. Сумую за часами коли всі програми були offline-first, і…

15.04.2025

Як працюють транзакційні комісії в мережах Bitcoin і Ethereum

Надсилаючи криптовалюту, багато новачків ставлять запитання: як працюють комісії та чому вони відрізняються в різних…

14.04.2025

Обережно, тепер вас можуть обдурити на співбесіді з роботодавцем

Нова афера набирає обертів — ось детальний розбір того, як фальшиві потенційні роботодавці намагаються вкрасти…

11.04.2025