Серед багатьох досвічених розробників існує думка, що 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 до свого фреймворку.
Цей текст з особистого блогу, опублікований з дозволу автора.
If you have found a spelling error, please, notify us by selecting that text and pressing Ctrl+Enter.
Favbet Tech – це ІТ-компанія зі 100% українською ДНК, що створює досконалі сервіси для iGaming і Betting з використанням передових технологій та надає доступ до них. Favbet Tech розробляє інноваційне програмне забезпечення через складну багатокомпонентну платформу, яка здатна витримувати величезні навантаження та створювати унікальний досвід для гравців.
Цей матеріал – не редакційний, це – особиста думка його автора. Редакція може не поділяти цю думку.
Сообщить об опечатке
Текст, который будет отправлен нашим редакторам: