laravel how to optimize a simple where query in one table - php

i have a simple where query that repeats in a foreach for some times that can be a lot really so here is my query :
for ($i = 0; $i < count($hasdate); $i++) {
$roomprice = RoomPricingHistory::
Where('accommodation_room_id', $hasroom[$i])
->where('from_date', '<=', $hasdate[$i])
->where('to_date', '>=', $hasdate[$i])
->get()->sortBy('created_at');
$lastget = last($roomprice);
$last_price = last($lastget);
if ($last_price) {
$final_price[] = $last_price->sales_price;
} else {
$has_not_capacity = $hasdate[$i];
}
}
so each time this runs it takes a bout 2,509.10ms in telescope and here is what the telescope shows me as the query which is running on table
select
*
from
`room_pricing_histories`
where
`accommodation_room_id` = 3
and `from_date` <= "2019-06-01 09:00:00"
and `to_date` >= "2019-06-01 09:00:00"
so any idea on how to optimize this query ??

Well, as a rule of thumb - don't run a query inside a loop.
You can use whereIn() for the querying multiple IDs
$roomIds = $hasroom // assume this has array of ids
$roomprice = RoomPricingHistory::
whereIn('accommodation_room_id', $roomIds)
->where('from_date', '<=', $fromDate)
->where('to_date', '>=', $toDate)
->get()->sortBy('created_at');

Related

OFFSET and LIMIT not working in laravel Eloquent?

I am trying to use offset and limit on Laravel eloquent.
$start_from = 0;
$limit = 2;
$invoices = Invoice::where('calculation_complete',0)
->offset($start_from)
->limit($limit)
->get();
Instead of giving me 2 record it is giving me all the records. Where it is going wrong I am using it on other places there it is working fine.
Laravel has own function skip for offset and take for limit.
Try this:
$start_from = 0;
$limit = 2;
$invoices = Invoice::where('calculation_complete',0)
->orderBy('id','DESC')
->skip($start_from)
->take($limit)
->get();
Or, you can use paginate:
$invoices = Invoice::where('calculation_complete',0)
->orderBy('updated_at', 'desc')->paginate($limit);

How to get limited data to paginating

$rowsPerPage = 50;
$num = 1;
$offsets = ($num - 1) * $rowsPerPage;
$data['trans'] = Transaction::withoutBranch()
->select('id', 'amount')
->where('payment_date', '>=', '2019-06-07')
->limit($offsets)
->get();
I'm using Laravel 4.2 to do the planning. I trying to get the data from data with 50 on the first page then the second page will get another new 50 data.
I did try the code but it still gets all of the data from the database.
Please try following:
$data['trans'] = Transaction::withoutBranch()
->select('id', 'amount')
->where('payment_date', '>=', '2019-06-07')
->limit($rowsPerPage)
->offset($offsets)
->get();

laravel slow query issue

I want to optimize my query I am executing with Laravel. I'm using MySQL for my project and I have a table named locations. It has more than 2 million records.
When I execute the code below it's too slow. How can I optimize my query to improve the speed?
foreach ($employees as $employee){
$percentage = 0;
if ($employee->position->zones->count() > 0) {
if($employee->position->zones->first()->workingzones->count() > 0) {
$workingZone = $employee->position->zones->first()->workingzones->last();
$tagCode = $employee->rfids->first()->rfid_id;
$zoneTime = DB::table('location')
->select(DB::raw('count(*) as count'))
->where('tagCode', $tagCode)
->where('xLocation', '>', $workingZone->x1)
->where('xLocation', '<', $workingZone->x3)
->where('yLocation', '>', $workingZone->y3)
->where('yLocation', '<', $workingZone->y1)
->where('locationDate', '>=',''.$currentDate.' 00:00:01')
->where('locationDate', '<=', $currentDate. ' 23:59:59')
->get();
$totalWorkedTime = DB::table('location')
->select(DB::raw('count(*) as count'))
->where('tagCode', $tagCode)
->where('locationDate', '>=',''.$currentDate.' 00:00:01')
->where('locationDate', '<=', $currentDate. ' 23:59:59')->get();
if ($zoneTime->first()->count == 0 || $totalWorkedTime->first()->count == 0) {
$percentage = 0;
}else {
$percentage = (int)ceil(($zoneTime->first()->count /12 )* 100 / ($totalWorkedTime->first()->count / 12));
}
}
}
$employee->percentage = $percentage;
}
You do a full ->get() twice and only use the ->first() result. When you just need 1, just use ->first() instead of ->get().
Also you can eagerload the position and zones while fetching the employees , and saving 2 additional queries per loop (- grouped eagerload queries on total), like this:
$employees = Employee::where(/*where foo here*/)
->with('position.zones')
->get();
And to consume less mem, chunk it.
Employee::where(/*where foo here*/)
->with('position.zones')
->chunk(200, function ($employees) {
foreach ($employees as $employee) {
// current code here with ->first() instead of ->get()
}
});
Adding indexes on the following columns should improve your performance:
xLocation
yLocation
locationDate
How to add indexes with an MySQL query:
https://dev.mysql.com/doc/refman/5.7/en/create-index.html
or if you use Laravel's migrations: https://laravel.com/docs/5.4/migrations#indexes
Edit:
Also: instead of doing the COUNT(*) on both select queries, use COUNT(`id`), so you don't count all columns, but only the id column

Putting orderby from highest to lowest in database query

1.I've a confusion on how to add sort orderby(highest to lowest) in my database query for the age.I've tried some few codes but it generates an error.Any help here is much appreciated.
public function ListOrgaScholar($ship_id){
$ship = Scholarship::find($ship_id);
$ship_age_from = $ship->ship_age_from;
$ship_age_to = $ship->ship_age_to;
$scholars = (new Scholar)->newQuery()->select('*');
$scholars->whereBetween(DB::raw('TIMESTAMPDIFF(YEAR,scholars.scholar_birthday,CURDATE())'),array($ship_age_from,$ship_age_to));
$scholars = $scholars->get();
}
2.Same us here.How to add orderby(highest to lowest) since it is two different where clause.The $ship_gpa_from and $ship_gpa_to are inputs of grade.
public function ListOrgaScholar($ship_id){
$ship = Scholarship::find($ship_id);
$ship_gpa_from = $ship->ship_gpa_from;
$ship_gpa_to = $ship->ship_gpa_to;
$scholars = (new Scholar)->newQuery()->select('*');
if($ship_gpa_from)
$scholars->where('scholar_GPA', '>=', $ship_gpa_from);
if($ship_gpa_to)
$scholars->where('scholar_GPA', '<=', $ship_gpa_to);
$scholars = $scholars->get();
}
Have you tried returning the results as collection and then applying collection functions on them? The code would look somewhat like this:
$scholarship = Scholarship::find($id);
$scholars = Scholar::all();
$selectedScholars = $scholars->filter(function ($item, $key) {
$scholarAge = Carbon::now() - $item->scholar_birthday //this depends on the value of scholar_birthday;
return ($scholarAge >= $scholarship->ship_age_from && $scholarAge <= $scholarship->ship_age_from);
})->sortBy("scholar_birthday");

Laravel 5 ; Using count on already filtered data without altering it

I'm running this code on Laravel. I'm adding filters/ordering if I receive them and I'm altering the query before running it and then paginate the results.
$aDatas = DB::table('datas');
if (!empty($aLocations)) {
foreach ($aLocations as $oLocation) {
$aDatas->orWhere('pc', '=', $oLocation->pc);
}
}
if (!empty($oFilters->note)) {
$aDatas->where('note', '>=', $oFilters->note);
}
if (!empty($oFilters->nb_comments)) {
$aDatas->where('nb_comments', '>=', $oFilters->nb_comments);
}
if (!empty($oOrder->type)) {
$aDatas->orderBy($oOrder->type, $oOrder->sort);
}
// echo $aDatas->where('note', '>=', 5)->count() ????
It's working fine.
But I'd like to use these results to count several parts of it.
The last line shows what I tried to do, counting how many rows in these filtered results have a note >= 5. But doing this will actually filter my original data.
I thought about assigning $aDatas to another variable and then count on this, but I'll have many counts and that seems dirty.
Is there a sweet way to do this ?
Just save your datas an replace the last line with this:
$datas =$aDatas->where('note', '>=', 5)->get();
echo $datas->count();
//use datas here for more action.
For all of your requirement, you might want to resolve in making several queries because a single query will not be able to do that(based from what I know)
//this is to get your total of note greater than 5
$query = DB::table('datas');
$query->where('note', '>=', 5);
$data = $query->paginate(10);
$count = $data->getTotal();
to get your other data
If you are working with pagination, use getTotal() instead
$query = DB::table('datas');
$query->select(
DB::raw('COUNT(stars) AS count'),
DB::raw('starts'),
);
$query->where('notes', '>=', 5);
$query->groupBy('stars');
$data = $query->get();

Categories