Научная статья на тему 'ОПТИМИЗАЦИЯ SQL-ЗАПРОСОВ В ВЕБ-ПРИЛОЖЕНИИ, НАПИСАННОМ НА RUBY ON RAILS'

ОПТИМИЗАЦИЯ SQL-ЗАПРОСОВ В ВЕБ-ПРИЛОЖЕНИИ, НАПИСАННОМ НА RUBY ON RAILS Текст научной статьи по специальности «Компьютерные и информационные науки»

CC BY
76
10
i Надоели баннеры? Вы всегда можете отключить рекламу.
Ключевые слова
RUBY ON RAILS / SQL / БАЗА ДАННЫХ / ACTIVE MODEL / ACTIVE RECORD / ПРОБЛЕМА N+1 ЗАПРОСОВ / LAZY LOAD / EAGER LOAD

Аннотация научной статьи по компьютерным и информационным наукам, автор научной работы — Никишанин Роман Олегович, Ямашкин Станислав Анатольевич

В статье описаны основные проблемы, с которыми сталкивается Ruby on Rails разработчик при написании программного кода, в котором происходит обращение к базе данных через SQL-запросы; описаны основные подходы, которые используются в Ruby on Rails для доступа к ассоциативным данным и ситуации, когда следует применять каждый из подходов.The article describes the main problems that a Ruby on Rails developer faces when writing program code that accesses the database through SQL queries; describes the main approaches that are used in Ruby on Rails to access associative data and situations when each of the approaches should be applied.

i Надоели баннеры? Вы всегда можете отключить рекламу.
iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.
i Надоели баннеры? Вы всегда можете отключить рекламу.

Текст научной работы на тему «ОПТИМИЗАЦИЯ SQL-ЗАПРОСОВ В ВЕБ-ПРИЛОЖЕНИИ, НАПИСАННОМ НА RUBY ON RAILS»

УДК 004.93

Информационные технологии

Никишанин Роман Олегович, магистр, Национальный исследовательский

Мордовский государственный университет им. Н.П. Огарева Ямашкин Станислав Анатольевич, кандидат технических наук, доцент кафедры автоматизированных систем обработки информации и управления, Национальный исследовательский Мордовский государственный университет

им. Н. П. Огарева

ОПТИМИЗАЦИЯ SQL-ЗАПРОСОВ В ВЕБ-ПРИЛОЖЕНИИ, НАПИСАННОМ НА RUBY ON RAILS

Аннотация: В статье описаны основные проблемы, с которыми сталкивается Ruby on Rails разработчик при написании программного кода, в котором происходит обращение к базе данных через SQL-запросы; описаны основные подходы, которые используются в Ruby on Rails для доступа к ассоциативным данным и ситуации, когда следует применять каждый из подходов.

Ключевые слова: Ruby on Rails, SQL, база данных, Active Model, Active Record, проблема N+1 запросов, lazy load, eager load.

Abstract: The article describes the main problems that a Ruby on Rails developer faces when writing program code that accesses the database through SQL queries; describes the main approaches that are used in Ruby on Rails to access associative data and situations when each of the approaches should be applied.

Keywords: Ruby on Rails, SQL, database, Active Model, Active Record, N+1 query problem, lazy load, eager load.

Введение

В настоящее время нередко возникает потребность в создании

высоконагруженных систем массового обслуживания, развернуты в сети Интернет. Это могут быть сервисы по продаже авиабилетов, торговые площадки, биржи и т.д. В таких системах необходимо оперировать большими объемами данных с довольно сложной структурой [1]. Если в качестве базы данных планируется использовать один из реляционных вариантов (Postgresql, Mysql), то она неизбежно обрастет множеством таблицы с различными связями. На этапе планирования очень часто в качестве инструмента для реализации подобных веб-сервисов выбирается веб-фреймворк Ruby on Rails [6].

RoR предоставляет множество инструментов для быстрой и эффективной разработки. Одними из таких инструментов являются библиотеки Active Model и Active Record, которые обеспечивают представление базы данных приложения в виде классов-моделей с определенной бизнес логикой, а также удобную работу с содержимым базы данных с помощью универсального ORM интерфейса [2; 3].

Однако на практике в процессе разработки реальных веб-приложений нередко возникают ситуации, когда код, в котором выполняется доступ к базе данных, выполняется достаточно медленно, что негативно сказывается на общем времени выполнения запроса и ожидания пользователем ответа с сервера. При масштабировании приложения это проблема может оказаться критической, поэтому важно писать оптимизированные запросы в базу данных. Зачастую это может быть связано с тем, что разработчик при написании программного кода использовал не подходящие под конкретную ситуацию ORM - методы для выполнения SQL-запросов и получения дочерних таблиц (моделей на языке ORM) [7].

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

1. Проблема N+1 запросов

"Проблема N + 1 запросов" - это проблема при работе с ассоциациями (таким образом в Active Model реализуются табличные отношения "один к

одному", "один ко многим" и "многие ко многим") [8]. В данном случае N - это количество записей, у которых берутся ассоциации. Например, у нас есть две модели User и Comment, которые связаны отношением "один к одному":

class User < ApplicationRecord

has_many :comments end

class Comment < ApplicationRecord belongs_to :user end

В коде нам необходимо получить массив записей пользователей и для каждого получить связанные с ним комментарии следующим образом:

users = User.all users.each do |user| comments = user.comments

# выполнить необходимые действия с комментариями end

В данной ситуации запросы в базу данных будут выглядеть следующим образом:

User Load (0.8ms) SELECT "users".* FROM "users" LIMIT $1 [["LIMIT", 11]] Comment Load (0.2ms) SELECT "comments".* FROM "comments" WHERE "comments"."user_id" = $1 [["user_id", 1]]

Comment Load (0.2ms) SELECT "comments".* FROM "comments" WHERE "comments"."user_id" = $1 [["user_id", 2]]

Comment Load (0.2ms) SELECT "comments".* FROM "comments" WHERE "comments"."user_id" = $1 [["user_id", 3]]

Comment Load (0.2ms) SELECT "comments".* FROM "comments" WHERE "comments"."user_id" = $1 [["user_id", 4]]

Comment Load (0.1ms) SELECT "comments".* FROM "comments" WHERE "comments"."user_id" = $1 [["user_id", 5]]

В результаты выполнения программного кода было выполнено 5 + 1

(количество пользователей в данном случае 5) запросов в базу данных. Если число пользователей возрастет, это может привести к серьезному падению производительности. Для решения данной проблемы в Active Record существуют специальные методы.

2. Lazy Loading и Eager Loading

В Ruby on Rails существует два варианта загрузки ассоциаций: Lazy Loading и Eager Loading. Lazy Loading - это подход, при котором ассоциации записей загружаются в память не сразу, а только в момент, когда они необходимы в коде и вызываются с помощью соответствующих методов. В Ruby on Rails он применяется по умолчанию при работе с ассоциациями. Lazy Loading позволяет сократить количество выделяемой памяти и SQL-запросов при получении исходных записей. Однако, если после этого мы будем использовать ассоциации каждой полученной записи в программном коде, это приведет к вызову дополнительных SQL-запросов, что было продемонстрировано ранее. Lazy Loading рекомендуется использовать только в том случае, если ассоциации не будут запрашиваться явно в программном коде или если данные из ассоциаций необходимы в SQL-запросе для исходных записей [4]. Для Active Record предоставляет специальный метод joins. Пример его использования:

users = User.all.joins(:comments).where("comments.body='test'") User Load (3.4ms) SELECT "users".* FROM "users" INNER JOIN "comments" ON "comments"."user_id" = "users"."id" WHERE (comments.body='test') LIMIT $1

Eager Loading - подход, при котором ассоциации заранее подгружаются в память и запрашиваются вместе с исходными записями или одним отдельным запросом в зависимости от используемых методов [5]. Данный подход увеличивает расход памяти, однако позволяет сократить количество SQL-запросов в тех случаях, когда ассоциации непосредственно запрашиваются в коде, что обеспечивает хорошую производительность при большом количестве записей. В Active Record существует несколько методов для запроса ассоциаций в формате Eager Loading: preload, eager_load и includes. Последний

метод является наиболее универсальным и чаще всего применятся на практике. Добавим Eager Loading в приведенный выше программный код и посмотри на SQL-запросы:

users = User.all.includes(:comments) users.each do |user| comments = user.comments

# выполнить необходимые действия с комментариями end

User Load (0.2ms) SELECT "users".* FROM "users" LIMIT $1 [["LIMIT", 11]] Comment Load (0.3ms) SELECT "comments".* FROM "comments" WHERE "comments"."user_id" IN ($1, $2, $3, $4, $5) [["user_id", 1], ["user_id", 2], ["user_id", 3], ["user_id", 4], ["user_id", 5]]

Количество запросов в базу данных значительно сократилось, и при увеличении кол-ва пользователей разница будет существенно возрастать.

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

Выводы

Таким образом, в данной статье была рассмотрена проблема 'N+1 запросов', которая является одной из основных причин низкой производительности программного кода в современных Ruby on Rails приложениях. Она возникает из-за неправильного использования способов подгруздки ассоциативных данных (eager loading и lazy loading). Методы, реализующие eager loading, следует использовать в тех случаях, когда мы явно запрашиваем доступ к ассоциативным данным в программном коде. Использование данного подхода позволяет решить проблему 'N+1 запросов'. В

свою очередь методы, реализующие lazy loading, должны применяться для формирования сложных SQL-запросов с использованием ассоциативных данных.

Библиографический список:

1. Афонин В. В. Основы анализа систем массового обслуживания / В. В. Афонин, С. М. Мурюмин, С. А. Федосин / — Текст: непосредственный // Научная электронная библиотека ELibrary.ru — 2003. — С. 234. — Режим доступа: https://www.elibrary.ru/item.asp?id=19581660 (дата обращения: 28.11.2022).

2. Документация Ruby [Электронный ресурс]: ruby-doc.org - Режим доступа: https://ruby-doc.org/ (дата обращения: 25.10.2022).

3. Официальная документация API Ruby on Rails [Электронный ресурс]: api.rubyonrails.org - Режим доступа: https://api.rubyonrails.org/ (дата обращения: 25.05.2022).

4. Preload, Eagerload, Includes and Joins [Электронный ресурс]: www.bigbinary.com - Режим доступа: https://www.bigbinary.com/blog/preload-vs-eager-load-vs-joins-vs-includes (дата обращения: 15.11.2022).

5. Различные методы загрузки ассоциаций в Ruby on Rails [Электроный ресурс]: habr.com - Режим доступа: https://habr.com/ru/post/191762/ (дата обращения: 15.11.2022).

6. Ruby on Rails по-русски [Электронный ресурс]: rusrails.ru - Режим доступа: http://rusrails.ru/ (дата обращения: 28.11.2022).

7. Rails N+1 queries and eager loading [Электронный ресурс]: dev.to -Режим доступа: https://dev.to/junko911/rails-n-1-queries-and-eager-loading-10eh (дата обращения: 18.11.2022).

8. Проблема N+1 [Электронный ресурс]: medium.com. - Режим доступа: https://medium.com/@croatech/rails-является-одним-из-самых-популярных-фреймворков-для-созданияmvp-minimum-viable-products-49a00a63137c (дата обращения: 18.11.2022).

i Надоели баннеры? Вы всегда можете отключить рекламу.