Don't assume the code and solution in this article is right for each query in your application.
If your database is set up properly, has the correct indexes and you (eager) load your relationships to avoid N+1 issues, you'll hardly run into performance issues on a day-to-day basis.
While developing vursion.io, which is a data-dense application with a lot of relationships, I eventually ran into a performance issue were too many models where being loaded.
My application was becoming slow and unresponsive as the amount of data increased and each record was initialized as an Eloquent model.
After a lot of research and a few failed attempts, it was clear to me I had to let the database do the hard work for me. Taking into consideration that:
After some code diving, I came up with a solution which was a combination of the Database Query Builder and the Eloquent fromQuery() method:
$query = DB::table('YourModelTable');
$models = YourModel::fromQuery($query->toSql())
The example above is focussing on the essentials and for demonstration purposes only! You should always try to use the Eloquent methods available on your model as much as possible.
A real-life example would look more like this:
$query = DB::table('SomeTable')
->selectRaw('YourModelTable.*')
->join('AnotherTable', 'SomeTable.id', '=', 'AnotherTable.SomeTableId')
->join('YourModelTable', 'YourModelTable.id', '=', 'AnotherTable.YourModelTableId')
->where('SomeTable.SomeColumnName', '=', '?');
$models = YourModel::fromQuery($query->toSql(), [$binding])
The result is one fast query and only the relevant models are loaded in the collection.
You can sneak things in your query which get appended to your model, although they are not existing attributes. Below is an example where a count is added to the query.
$query = DB::table('SomeTable')
->selectRaw('DISTINCT(YourModelTable.id), YourModelTable.*, count(SomeTableId) AS counter')
->join('AnotherTable', 'SomeTable.id', '=', 'AnotherTable.SomeTableId')
->join('YourModelTable', 'YourModelTable.id', '=', 'AnotherTable.YourModelTableId')
->where('SomeTable.SomeColumnName', '=', '?')
->groupBy('YourModelTable.id');
$models = YourModel::fromQuery($query->toSql(), [$binding])
@foreach ($models as $model)
{{ $model->counter }}
@endforeach
Always check the output of explain to see if you need to optimize your joins or database indexes. I can highly recommend Kai Sassnowski's talk at Laracon EU 2018 on 'Things every developer absolutely, positively needs to know about database indexing'.
Use a tool of your choice like Laravel Debugbar or Laravel Telescope to detect performance issues in your application.
A lot of database performance issues only occur with a large dataset. Always test your queries on both small and large datasets.