Eloquent - это мощная ORM, реализация шаблона ActiveRecord, позволяющая комфортно работать с базой данных, например, с помощью таких вещей: модели, связи, скоупы, события, аксессоры, мутаторы, касты...
Но, к сожалению, у удобства есть своя цена и в случае с Eloquent - это производительность из-за дополнительного функционала.
Некоторые проекты и команды полностью отказываются от Eloquent в пользу DB фасада и пропагандируют свой выбор как неопровержимо верное решение. Данная тема периодически вспыхивает в чатах и почти всегда это переходит в холивар. Вместо долгих рассуждений предлагаю сразу взглянуть на цифры.
# Условия
Замер был сделан на php 8.1, mysql 8.0, laravel 9. Нас интересует только разница между Eloquent и DB, время выполнения самих запросов относительно и будет напрямую зависеть от конфигурации железа и ПО.
Модель использовалась пустой, без событий, кастов и трейтов, в реальном проекте чем больше будет навешано на модель функционала, тем медленнее будут отрабатывать запросы, что логично.
Значения средние из 100 прогонов, в секундах.
# Чтение
Чтение, строк | Eloquent | DB | Разница | Эффективность |
---|---|---|---|---|
1 | 0.00098 | 0.00068 | 0.0003 | +44% |
10 | 0.00136 | 0.00071 | 0.00065 | +91% |
100 | 0.00373 | 0.00088 | 0.00285 | +320% |
1 000 | 0.02461 | 0.00289 | 0.02172 | +750% |
10 000 | 0.22458 | 0.02122 | 0.20336 | +950% |
# Результаты чтения
В чтении данных DB выигрывает у Eloquent, но существенно сказывается только на больших объёмах данных, запрос на 10К строк отработал в 9 раз быстрее.
Но при этом мы лишаемся всех удобств при работе с БД. В реальности чаще всего нам потребуется дополнительная обработка данных, связи придётся доставать и компоновать вручную, обновлять данные тоже необходимо вручную отдельным запросом... в общем как в старые добрые...
Имеет ли смысл? Лично я не вижу смысла отказываться от Eloquent, ибо с таким же успехом можно отказаться и от самой Laravel. Запросы можно переписать только там где это действительно необходимо. В более или менее среднем приложении придётся писать дополнительно "репозитории" или сервисы, чтобы навести порядок и контролировать разбросанные и несвязные запросы, что приведёт рано или поздно к кастомной ORM, но из костылей и палок.
# Запись
Запись | Eloquent | DB | Разница | Эффективность |
---|---|---|---|---|
1 строка | 0.00683 | 0.00605 | 0.00078 | +12% |
1 строка | 0.00736 | 0.00749 | -0.00013 | -1% |
1 строка | 0.00683 | 0.00589 | 0.00094 | +16% |
1 строка | 0.00617 | 0.00578 | 0.00039 | +6% |
# Результаты записи
Поскольку create() может сохранить только одну запись за раз, то не получится его сравнить с insert() в записи большого количества строк. Один insert() очевидно будет работать быстрее, чем create() в цикле. Поэтому тестировать имело смысл только запись одной строки.
Преимущество DB при записи отсутствует. В некоторых прогонах результат даже оказался хуже. Различия можно списать на погрешность измерений.
Если необходимо вставить большое кол-во записей, то конечно insert() это сделает эффективнее одним запросом, иначе смысла не вижу.
# Выводы
Если не хватает производительности Eloquent, то проблема скорей всего не решится отказом в пользу DB, а если и решится, то надолго ли и как это повлияет на поддержку приложения и скорость разработки в перспективе?
В погоне за производительностью можно пойти ещё дальше (немного) и отказаться от QueryBuilder и писать чистые SQL-запросы с DB или с PDO (и так до «чистого кода» можно продолжать). Вопрос в том, действительно ли это решает проблему не принося новую? Возможно, стоит рассмотреть другие способы хранения данных или увеличить производительность с помощью железа.
Универсального ответа здесь быть не может, Eloquent позволяет быстро вести разработку и влечёт за собой расходы ресурсов, как и любая другая логика. На самом деле, с таким же успехом можно сравнивать производительность фреймворков и чистого php...