Привет, я Валерио, инженер-программист из Италии и технический директор Inspector.
В этой статье я хотел бы поделиться набором стратегий оптимизации норм, которые я использую почти в каждом бэкэнд-сервисе, над которым работаю.
Я уверен, что каждый из нас жаловался на то, что машина или приложение работают медленно или даже не работают, а затем проводили время у кофемашины в ожидании результатов длительного запроса.
Как мы можем это исправить?
Давайте начнем!
Почему так много проблем с производительностью возникает из-за базы данных?
Мы часто забываем, что каждый запрос не является независимым от других запросов.
Если один запрос выполняется медленно, это вряд ли повлияет на остальные … верно?
База данных используется всеми процессами, которые выполняются в вашем приложении одновременно. Даже один плохо спроектированный доступ может снизить производительность всей системы.
Так что будьте осторожны с ” ничего страшного, если этот блок кода не оптимизирован” . Один медленный доступ к базе данных может привести к перегрузке вашей базы данных, что приведет к негативным последствиям для ваших пользователей.
В чем проблема N+1?
Это типичная проблема, возникающая при использовании ORM для взаимодействия с базой данных. Это не проблема с кодированием SQL.
Когда вы используете ORM, такой как Eloquent, не всегда очевидно, какие запросы будут сделаны и когда. Для этой конкретной проблемы мы говорим об отношениях и нетерпеливой нагрузке.
Любая ФОРМА позволяет вам объявлять отношения между сущностями, предоставляя отличный API для навигации по структуре нашей базы данных.
” Статья и автор” отличный пример.
/*
* Each Article belongs to an Author
*/
$article = Article::find("1");
echo $article->author->name;
/*
* Each Author has many Articles
*/
foreach (Article::all() as $article)
{
echo $article->title;
}
Но нам нужно кодировать с осторожностью, используя отношения внутри цикла.
Взгляните на приведенный ниже пример.
Мы хотим добавить имя автора рядом с названием статьи. Благодаря ФОРМЕ мы можем ориентироваться в соотношении “один к одному” между статьей и автором, чтобы узнать ее название.
Это звучит очень просто:
// Initial query to grab all articles
$articles = Article::all();
foreach ($articles as $article)
{
// Get the author to print the name.
echo $article->title . ' by ' . $article->author->name;
}
Мы попали в ловушку.
Этот цикл генерирует 1 начальный запрос для захвата всех статей:
SELECT * FROM articles;
и N запросов, чтобы заставить автора для каждой статьи напечатать поле “имя”. Также, если автор всегда один и тот же.
SELECT * FROM author WHERE id = [articles.author_id]
N +1 запросов точно.
Это может показаться не такой уж важной проблемой. Пятнадцать или двадцать запросов могут быть рассмотрены как не требующие немедленного решения проблемы. Будьте внимательны и ознакомьтесь с первой частью этой статьи:
- База данных – это ресурс, общий для всех процессов.
- Машина базы данных имеет ограниченные ресурсы, или если вы используете управляемую службу, большая загрузка базы данных может повлечь за собой дополнительные затраты.
- Если ваша база данных расположена на отдельном компьютере, все данные необходимо передавать с дополнительной задержкой в сети.
Как упоминалось в документации Laravel , мы можем легко столкнуться с проблемой запроса N + 1, потому что при доступе к красноречивым отношениям в качестве свойств ( $article->author ) данные отношений “лениво загружаются”. Это означает, что данные о взаимоотношениях фактически не загружаются до тех пор, пока вы не получите первый доступ к свойству.
Однако мы можем загрузить все данные отношений с помощью простого метода, поэтому, когда вы получите доступ к красноречивым отношениям как свойству, он не будет запускать новый запрос, потому что данные уже загружены ORM.
Эта тактика называется “нетерпеливая нагрузка” и поддерживается всеми ORM.
// Eager load authors using "with".
$articles = Article::with('author')->get();
foreach ($articles as $article)
{
// Author will not run a query on each iteration.
echo $article->author->name;
}
Красноречивый предоставляет метод с() для нетерпеливых отношений загрузки.
В этом случае будут выполнены только два запроса.
Первый необходим для загрузки всех статей:
SELECT * FROM articles;
Второй – с помощью методов with() и он восстановит всех авторов:
SELECT * FROM authors WHERE id IN (1, 2, 3, 4, ...);
Красноречивый отобразит внутренние данные для использования в обычном режиме:
$article->author->name;
Долгое время я думал, что явное объявление количества полей в запросе select не приведет к значительному повышению производительности, поэтому я воспользовался простотой получения всех полей для своих запросов.
Кроме того, жесткое кодирование списка полей для определенного выбора не является простым в обслуживании оператором кода.
Самая большая ошибка, стоящая за этим аргументом, заключается в том, что это может быть правдой с точки зрения базы данных.
Но мы используем ORM, поэтому данные, выбранные из базы данных, будут загружены в память на стороне PHP для управления ORM. Чем больше полей мы захватим, тем больше памяти займет процесс.
Laravel Красноречивый предоставляет метод “выбора” для ограничения запроса только теми столбцами, которые нам нужны:
$articles = Article::query()
->select('id', 'title', 'content') // Only the fields you need
->latest()
->get();
Исключая поля, PHP не должен обрабатывать эти данные, поэтому вы можете значительно сократить потребление памяти.
Отказ от выбора всего также может повысить производительность сортировки, группировки и объединения, поскольку таким образом база данных может экономить память.
Представления – это запросы ВЫБОРА, построенные поверх других таблиц и сохраненные в базе данных.
Когда мы выполняем SELECT для одной или нескольких таблиц, базе данных необходимо скомпилировать вашу инструкцию SQL, убедиться, что она не содержит ошибок, и выполнить выбор данных.
Представления представляют собой предварительно скомпилированные операторы ВЫБОРА, поэтому MySQL может немедленно выполнить запрос подчеркивания.
Кроме того, MySQL, как правило, умнее PHP, когда дело доходит до фильтрации данных. По сравнению с использованием функций коллекций или массивов в PHP наблюдается большой прирост производительности.
Если вы хотите узнать больше о возможностях MySQL для приложений с интенсивным использованием баз данных, загляните на этот удивительный веб-сайт: https://www.mysqltutorial.org/
Прикрепите красноречивую модель к представлению
Представления являются “виртуальными таблицами”, но с точки зрения НОРМЫ они выглядят как обычные таблицы.
Вот почему мы можем создать красноречивую модель для запроса данных внутри представления.
class ArticleStats extends Model
{
/**
* The name of the view is the table name.
*/
protected $table = "article_stats_view";
/**
* If the resultset of the View include the "author_id"
* we can use it to retrieve the author as normal relation.
*/
public function author()
{
return $this->belongsTo(Author::class);
}
}
Отношения работают как обычно, также приведение, разбивка на страницы и т. Д., И больше никакого влияния на производительность.
Отличная работа!
Я надеюсь, что один или несколько из этих советов помогут вам создать более надежный и масштабируемый программный продукт.
Я использовал красноречивый ORM для написания примеров кода, но вы можете использовать эту стратегию со всеми основными ПЗУ таким же образом.
Как я часто говорю, инструменты должны помочь нам реализовать эффективную стратегию. Ни стратегии, ни вечеринки.
Новичок в инспекторе?
Создайте среду мониторинга, специально разработанную для разработчиков программного обеспечения, избегая любой конфигурации сервера или инфраструктуры, с которой многие разработчики ненавидят иметь дело.
Благодаря Inspector у вас никогда не возникнет необходимости устанавливать что-либо на уровне сервера или выполнять сложную настройку в вашей облачной инфраструктуре.
Инспектор работает с облегченной библиотекой программного обеспечения, которую вы можете установить в свое приложение, как и любые другие зависимости. В случае Laravel в вашем распоряжении наш официальный пакет Laravel . Разработчикам не всегда удобно устанавливать и настраивать программное обеспечение на уровне сервера, поскольку эти установки не входят в жизненный цикл разработки программного обеспечения или даже управляются внешними командами.
Посетите наш веб-сайт для получения более подробной информации: Посетите наш веб-сайт для получения более подробной информации:
Оригинал: “https://dev.to/inspector/make-your-application-scalable-optimizing-the-orm-performance-jbf”