Laravel Query efficiency difference - php

Please could somebody tell me which one is most efficient select in Laravel:
$car = Car::all(); ------- $car = Car::find();
$car = DB::table('car')->get(); ------ $car = DB::table('car')->first();

Your first approach:
$car = Car::all(); ------- $car = Car::find();
Makes use of Eloquent. This means, all the rows received from the query will be hydrated to Model instances, and all of those will be injected into an instance of Collection (for multiple elements, of course). This is useful because you then will have all the benefits that this brings. However, this comes with a little decrease on performance (understandable)
Your second one:
$car = DB::table('car')->get(); ------ $car = DB::table('car')->first();
Uses the Query Builder instead. The results (as a whole) will be also casted into an instance of Collection, but its items will be simple arrays. This means that the process will be faster (more performant) but on detriment of not having all the cool features of Eloquent.
There's even a more performant option: Using raw queries. That also has tradeoffs: Results are not hydrated into a Collection instance.
Which one to use? It depends on your needs. Usually I go for the Eloquent option. I use the Query Builder directly when I need to make queries to big databases and need speed.

For me most efficient is selecting from the Model: like Car:all(), but it's always better if you use pagination or just don't take all of the records from the database with all() method.
But selecting with DB is a bit faster and in some cases maybe it would be better to use.
In the end, it always depends on what`s your problem and which way do you want to solve it.
for a better understanding I recommend you to watch this video and after that maybe keep going to search for some more information or just try it out yourself.
https://www.youtube.com/watch?v=uVsY_OXRq5o&t=205s

Related

Will I get better performance if I use COUNT query instead of looping through entities in Symfony 4?

For example I need to get review count, one way of doing it is like this:
public function getActiveReviews()
{
return $this->getReviews()->filter(function(Review $review) {
return $review->isActive() && !$review->isDeleted();
})->count();
}
Another way is to use Query Builder like this:
$qb = $this->createQueryBuilder('r')
->where('r.active = true')
->andWhere('r.deleted = false')
->select('count(r)')
Which way will give me better performance and why?
Of course count query will be faster because it will result into single SQL query that will return single value.
Iteration over entities will require:
Run of SQL query for fetching data rows
Actual fetching of data
Entity objects instantiation and persisting fetched data into them
Depending on amount of affected data difference may be very big.
The only case when running count over entities may be fast enough is a case when you already have all entities fetched and just need to count them.
It depends on Symfony count() implementation, but you probably will. Usually RDBMS counts its rows quicker internally, and it requires much less resources.
In first case you request a whole rowset, which can be huge, then you iterate through it, you apply your filter function to every row, and then you just look at your filtered rowset size and drop everything. (But, of course, this might be optimized by your framework somehow).
In second case you just ask the database how much rows it has satisfying the criteria. And DB returns you a number, and that's all.
As other people said, the only case when first choice might be quicker is when you have already cached rowset (no need to connect to DB) — and when your DB connection is very slow at the same time.
I saw databases which were slow on some COUNT requests (Oracle) on big tables, but they were still faster than PHP code on same rowset. DBs are optimized for data filtering and counting. And usually COUNT request are very fast.

Unite/join Database and Eloquent's model query in Laravel 5.2

I have to check if an user is online (in-game), and if he's not then do another checks to perform a sql update.
Actually, I have these two queries.
$isOnline = DB::connection('mssql')->table('USER_STAT')->where('user_id', $userID)->value('ConnectionStat');
$character = Character::where('acc_id', $userID)->where('Name', $characterName)->firstOrFail();
Is there a way I can use union or join in order to save a DB query? I believe this is not a good practice, and some better method is out there, which I can't find in the docs.
I tried something like this, but without success:
$character = Character::where('acc_id', $userID)->where('Name', $characterName)->firstOrFail();
$result = DB::connection('mssql')->table('USER_STAT')->where('user_id', $userID)->union($character)->get();
Thanks in advance!
Using a relation in your Character Model to the Model of the USER_STAT table you can easily lookup the things you need to determine if an update somewhere is needed.
Eloquent Relationships
This does not consolidate the queries into one, like with a join, but they are not heavy anyway, and using the ORM to the fullest will have more significant advantages in the long run.
If you think you must use an SQL-join you must stick to the querybuilder, but the ORM is usually the better choice
Query Builder Joins

Get data from one table using one query and filter different rows into separate variables (Laravel 5.1)

I understand the question might not be very clear but here is my situation. I'm using laravel 5 and i'm developing a CRM system. I have placed Marital Status and Sex/Gender into one Lookup table. Whenever i get the values from the database and pass it to the view, i have two separate queries.
$sexes = DB::table('Lookups')
->where('ValueType', '=', 'Sex')->get();`
$marstatus = DB::table('Lookups')
->where('ValueType', '=', 'Marital Status')->get();`
return view('clients.edit',compact('client'))
->with('sexes', $sexes)
->with('marstatus ', $marstatus );
This code actually works and i am able to get both the marital status and sex/gender on my view.
So, here is my question
Doesn't this mean that i am sending a query to the database twice which affects performance even if it is small
Isn't there a way to query all the values from the lookup table in one query and filter out the values on the controller. So it can be something like
$Lookups = DB::table('Lookups')
and then filter the $Lookups variable and assign it into two different variables ($sexes and $marstatus) based on my filter criteria. i.e ($sexes is for values that have ValueType = 'Sex' ...)
Which one is better for performance. Sending a query twice or three times or just filtering the data on the controller.
1) Yes it does. Just install Laravel Debugbar and see it yourself. It's a very handy tool strongly recommended.
2) Yes you can do that, laravel has nice helper functions for that type of needs:
$collection = collect(DB::table('Lookups')
->whereIn('ValueType', ['Marital Status', 'Sex'])
->get());
$marstatus = $collection->filter(function($item) {
return $item->ValueType == 'Marital Status';
});
$sexes = $collection->filter(function($item) {
return $item->ValueType == 'Sexes';
});
What this does is, it converts the result array to a Laravel Collection so that you can use the filter function. You can also use array_filter function to filter without converting the result array to a collection.
3) Databases are always one of the primary bottlenecks, the fewer the query number the better. However this should not be a general rule especially when cache is used. And for example making joins or subqueries to reduce the number of queries would be deadly mistake on some cases.
Performance is a huge subject. I'd recommend you to start with the Laravel Debugbar to compare the memory usage, number of queries etc. and investigate more on various techniques including cacheing and design patterns too. Accessing the tables directly within the controller is not a very good idea in the first place...
Yes it does mean that. How big is your Lookups table?
You probably mean $lookups = DB::table('Lookups')->all(); or perhaps consider using an Eloquent model class instead, e.g. $lookups = Lookup::all(); Perhaps you may want to cache the result if the table is small? e.g. use the Cache classes in Laravel.
Better for performance would be to use the cache.
It is belong to your query Data I mean your lookups table data.
You can write the query like this in one time:
$sexes_marital_status= DB::table('Lookups')->where('ValueType', '=', 'Sex')
->orWhere('ValueType' '=', 'Marital Status' )
->get();
return view('clients.edit',compact('client'))
->with('sexes_marital_status',$sexes_marital_status);
and this is better that you send your query in one time.
`

Query Laravel Result Set

I am looking to do several queries using eloquent which are all to be returned to a single view and was wondering if there was a better way to do it than querying the database multiple times?
For example returning all the records then pulling sub sets of data from that?
At the moment I have something similar to:
$one = User::queryOne();
$two = User::queryTwo();
$three = User::queryThree();
etc
However I was thinking it would be better if it was possible to do something like:
$users = User::all();
$one = $users->where('created_at')...
$two = $users->where('modified_at')..
Obviously the above doesn't work but it it possible to do something like this?
Or is it best just to query the database separately each time?
From a pragmatic point of view, it's 'better' to do multiple queries, because it takes you less time to write them, and they are easier to read and debug. If you want to do it with one DB query, and then grabbing subsets out of them, you'd have to write your own convoluted logic, or perhaps a new Laravel collection class. And then someone else comes along and wonders, "What is going on in this code?"
Typically programmer time is the most constrained resource in a project. When you get done, if you find that the multiple database queries are a bottleneck, then think about re-writing it.
If you do decide to do one query, you can probably order the data by the fields you want for the criteria. Then loop through the result set, adding the rows to a new array each time the specified field's value changes. That's the simplest logic I can think of offhand.
What version of laravel are you using? In 5.1 you can do where on collections here. In 4.2 you can do so with callbacks here
EDIT
for 4.2 try something similar to this
$users = User::all();
$one = $users->filter(function($user)
{
if($user->age > 20){
return true;
}
return false;
});
Laravel Eloquent returns a Collection as a result.
You could use a foreach statement or use the build in Collections functions you could manipulate the results and create the sub-results.
For example you could use filter and do something like this:
$users = User::all();
$one = $collection->filter(function ($item) {
return $item->created_at >= time() - (24*60*60); // created the last day
});
$filtered->all();
Whether it is the best method depends on the application and the amount of data you are trying to fetch/process.
If you have only a few records from ::all(), then doing so might be a good approach (although using the collections functions you have to run three filters across your data).
If you have a lot of records from ::all() then it is preferably to use three different queries to the database (especially if the results will only be a few records).

OO performance question

I will be quick and simple on this.
Basically I need to merge multiple Invoices(Object) quickly and fast.
A simple idea is to
$invoice1 = new Invoice(1);
$invoice2 = new Invoice(2);
$invoice3 = new Invoice(3);
$invoice1->merge($invoice2,invoice3);
$invoice1->save();
Since each object will query it's own data, the number of queries increase as the number of invoices needed to be merge increases.
However, this is a case where a single query
SELECT * FROM invoice WHERE id IN (1,2,3)
Will suffice, however the implementation will not be as elegant as the above.
Initial benchmarks on sample data indicates a 2.5x-3x decrease in speed on the above due to the sheer number of mysql queries.
Advice please
Use an Invoice factory. You ask it for invoices using various methods. newest(n) get(id) get(array(id,id,id)) so on, and it returns arrays of invoices or single invoice objects.
<?php
$invoice56 = InvoiceFactory::Get(56); // Get's invoice 56
$invoices = InvoiceFactory::Newest(25); // Get's an array of the newest 25 invoices
?>
Could you make the Invoice object lazy and let merge load everything that hasn't been loaded?
Make sure you work on the same db connection all the time. Check that it does not reconnect in one script execution thread.
I could suggest looking into using an actual ORM (object relational mapping) in order to create a seperation between your actual queries and the objects used.. Take a look at Propel or (my favorite) Doctrine (version 2 is very easy to use)
That way you could have exactly what you want in just the same amount of code...

Categories