- PVSM.RU - https://www.pvsm.ru -

Как прокачать belongs_to чтобы работал в два раза быстрее (database_validations gem)

В данной статье, я покажу почему нужно использовать db_belongs_to из database_validations [1] гема вместо привычного нам belongs_to.

Я уверен, что большинство из вас знакомо с belongs_to из ORM ActiveRecord. Но знаете ли вы, что инициализация связи с помощь belongs_to в вашей модели также добавляет валидацию на существование связи. Это происходит потому, что belongs_to имеет опцию optional: false по умолчанию.

Таким образом, каждый раз когда вы сохраняете новый объект или обновляете существующий, вы выполняете дополнительный SQL SELECT запрос на каждую из ваших связей.

Пример

class User < ActiveRecord::Base
  belongs_to :company
  belongs_to :country
end

user = User.first
user.update(some_field: 'something')
# В первую очередь сделает два дополнительных запроса SELECT, чтобы узнать, что связи `company` и `country` существуют

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

user.update(...)
user.company.destroy!
=> команда будет выполнена без ошибок, таким образом, в базе данных будет храниться пользователь без связи с компанией, что нарушает целостность нашей базы данных (если изначально не было задумано обратное)

Чтобы решить данную проблему, вы можете добавить соответствующее ограничение внешнего ключа (foreign key constraint) в вашу базу данных. Имея данное ограничение, вы всегда будете уверены, что данная связь существует.

Что насчет производительности? Зачем нам делать SELECT запросы к базе данных, если мы уже уверены, что целостность данных будет соблюдена (с использованием ограничения внешнего ключа)?

Ответ прост — не нужно. Но, чтобы это стало возможным, нам нужно решить проблему обработки исключения ActiveRecord::InvalidForeignKey, которое мы получаем, когда пытаемся сохранить отсутствующую в базе данных связь. Это необходимо, чтобы иметь такое же поведение, как с belongs_to, чтобы errors включал такие же ошибки.

Чтобы не писать всю обработку самостоятельно, вам пригодится database_validations гем [1]. Данный гем уже включал в себя validates_db_uniqueness_of, который понравился людям (пост на хабре [2]) и теперь имеет db_belongs_to, который очень легко внедрить в ваш проект. db_belongs_to улучшает производительность и гарантирует целостность данных.

Метод делает несколько вещей за вас:

  • Проверяет существование правильного ограничения внешнего ключа в базе данных во время запуска приложения;
  • Парсит исключения базы данных и предоставляет соответствующие ошибки для errors вашего объекта;
  • Исключает необходимость исполнения лишних SQL запросов к базе данных;

Я рекомендую вам использовать database_validations [1] в ваших проектах. Данный гем уже протестирован в production окружении и показал себя очень хорошо. Несмотря на его простоту реализации, он может сильно улучшить производительность вашего проекта, т.к. чем больше вы используете его, тем больше сохраняете, ознакомьтесь с групповыми бенчмарками [3] для деталей.

Любые отзывы приветствуются! Признательны за любой вклад в проект!

Автор: djezzzl

Источник [4]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/ruby/300853

Ссылки в тексте:

[1] database_validations: https://github.com/toptal/database_validations

[2] пост на хабре: https://habr.com/post/431298/

[3] групповыми бенчмарками: https://github.com/toptal/database_validations#composed-benchmarks

[4] Источник: https://habr.com/post/431734/?utm_source=habrahabr&utm_medium=rss&utm_campaign=431734