Eloquent VS Facade DB

Август, 2022

Холивар

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...