Laravel search result is too slow - ajax

I need to build search functionality in my website. So far I have implemented the query in eloquent. It is like this,
`$syukko = Syukko::where('category', $cat)
->where('status', 1)
->get();`
Now, this website may have a large database. My tester tested it and reported that, it was performing too slow. I tried to use paginate to show 20 results per page. Still the speed was not improving.
One colleague suggested me to use AJAX. My question is does AJAX search perform faster than basic eloquent in pgsql? (live search is not necessary)
Also, currently I don't have large database with my machine. I write the code and send it to tester. Can I use any tool to get query time in localhost?

Just using ajax won't increase the speed, you need to optimize your query and use it properly to improvise the speed. As #duy Said you can do the indexing to improve the speed.
Laravel Pagination: Default laravel pagination runs count query to get the total records, which might take time if you are querying a large database.
You might try a custom pagination will increase the speed.
function showSearchR(Request $request){
$page = (isset($request->page))?$request->page:1;
$limit = 20;
$offset = ($page-1)*$limit;
$syukko = Syukko::where('category', $cat)
->where('status', 1)
->offset($offset)->limit($limit)
->get();
}
To get the query time you can use laravel query log:
Enable the query log by DB::enableQueryLog(); then use this code after excuting a query dd(DB::getQueryLog())

In this case, you have to create database index on category and status in order to increase database performance.
Ajax cannot improve performance a lot, because finally you should use eloquent to access database and return the data.

Related

how make a laravel pagination component?

I have a slider component with a back and forward button and I want to get data in sort of pagination how can I do this?
I just want to do this without using Vue.js or livewire just laravel , JS and JQuery.
Laravel's Query Builder provides a paginate method that gives you a LengthAwarePaginator. Normally, you would render this in a blade view with $items->links(), but instead you can convert its result to JSON (https://laravel.com/docs/8.x/pagination#converting-results-to-json). That way you can use the results in JavaScript any way you'd like.
First, why using slider to create a pagination? there are better approach like lazy load, filter column, and simple pagination. lazy load is best for performance i guess.
If you insist to create a slider component, just wondering, how many data that you have? and how many data that you want to retrieve to screen? Imagine, you have more than 1.000.000 rows in your database, you sure wouldn't want to query for them all for real time updates to your screen. Why i tell you 'query them all'?
Let me tell you, if you do a pagination using laravel default pagination (using limit and offset), the flow behind this is like this:
DB will select all of your rows that you have
DB will limit your row depends on limit parameter
DB will scan row one-by-one to match the offset that you want
DB will retrieve the data that you want
With that flow, that's why pagination (limit & offset) is not good enough if you have a lot of data. The solution is change your pagination logic from limit & offset to query like this (case: auto incremental id):
SELECT
*
FROM
payments
WHERE
Id > 15
LIMIT 20
or for descending approach, you can query like this:
SELECT
*
FROM
payments
WHERE
Id < 50
ORDER BY Id DESC
LIMIT 20
Then in laravel, send a json that include a pagination data. So, in javascript you just have to align the pagination data with library or your own pagination logic.

Laravel Backpack select2_from_ajax without Pagination

I'm using the Laravel Backpack (v4.0) Admin / Crud. I'm implementing the select2_from_ajax field on my users table. This field requires that you return a query using the paginate() method.
$results = User::where('email', 'LIKE', '%'.$search_term.'%')->paginate(10);
This works, but returns results very slow (10+ seconds). I feel that the paginate() method is what is causing this to take along time to render. If I perform the query directly on the database it takes less then 500ms to return. I have indexes on the email field so that is not what is causing the problem. The users table is ~300k rows.
Does anyone know of a way to alter this so that I can perform an exact match query like below? I don't need it to return multiple results.
$results = User::where('email', '=', $search_term)->first();

How to Paginate Multiple Models in Laravel without overworking the memory

Im trying to figure out the best way to paginate in laravel when i am working with big datasets, the method i am using now is overworking the memory. this is what i am doing: i query from multiple tables, map the results etc, then merge multiple collections, and only after that do i paginate it, i realized though that this is a really bad way of going about this, because i am querying way to much data for no reason, and as the data grows the slower it will become.
the question is what would be the correct way?
i thought maybe i would paginate and then work with the data, the issue is that for instance if i was trying to sort all the merged data by date i wouldn't be getting the proper results because one table may have less data then the other...
here is some of the code to help with clarifying the question
first i will query two tables orders table and transactions table
$transactions = Transaction::all();
$orders = Order::all();
then i will send this all to a action to map it all and format it the way i need to with laravel resources
return $history->execute(['transactions' => $transactions, 'orders' => $orders]);
what this action does is simply map all the transactions and return a resource, then it will map all the orders and return resources for them as well, after which it will merge it all and return the result.
then i take all of this and run it through a pagination action which uses the Illuminate\Pagination\LengthAwarePaginator class.
the results are exactly the way i want them its simply a memory overload.
i tried paginating first instead of doing
$transactions = Transaction::all();
$orders = Order::all();
i did
$transactions = Transaction::orderBy('created_at' 'desc' )->paginate($request->PerPage);
$orders = Order::orderBy('created_at' 'desc' )->paginate($request->PerPage);
and then run it through the action that returns resources.
there are a few issues doing this, firstly, i will no longer get back the pagination data so the app won't know the current page or how many records there are, secondly, if for example the orders table has 2 records, and the transactions table has 10 records, event though the dates of the orders table is after those of the transactions table they will still get queried first.
Use chunk method or paginate
Read documentation.

Laravel Search Model

Im new to laravel and have completed a project on the latest version laravel 5.6
However, the only thing that is pending to learn and implement is the search functionality which is the core of every application. The application i have coded is a huge project and i do not want to mess it up so would like to learn how search functionality works in order to implement in multiple sections of the project.
Let's say i have a the following models 1.Country 2.State 3.City 4.Professional_Categories 5.Professionals and i have added the relations in the models accordingly
I fetch the records normally using the following code
public function index()
{
$categories = ProfessionalCategory::all();
$topprofessionals = Professional::where('status', 1)->limit(12)->get()->sortByDesc('page_views');
$professionals = Professional::where('status', 1)->latest()->paginate(9);
return view('professionals.index',compact('professionals', 'categories', 'topprofessionals'));
}
I can pull up Countries, States and Cities as i pulled in categories and with foreach i can display them in the select box. Or i could use pluck('name', 'id') that works good too. But i have never tried search queries.
I want a search form on the professionals page where a user can select country, state, city, category and type keywords in locality and professional name to find the professionals. My next step would be to learn dependent dropdown for country, state and city.
And how the results can be displayed on the view file where im currently fetching records with foreach($professionals as $professional)
I do not need code, but just a basic example on how these kind of things work in laravel. Once i learn the basics i want to implement auto suggest from database and things like that. And a single form to search all the models.
It sounds like you'll need full text searching across a number of tables and associated columns. I'd recommend using Laravel Scout or a similar service (such as elastisearch) for this.
These will index your records in a way to allow for fast and efficient fuzzy searching. Using Scout as an example, you can directly query on your models like:
$orders = App\Order::search('Star Trek')->get();
Searching with Scout
This will save you from writing numerous queries using LIKE which becomes very slow and inefficient quite quickly.
Using Eloquent you might do something like this in your Controller:
public function search(Request $request)
{
$countries = Country::where('name', 'like', '%' . $request->search_value . '%')->get();
}
This will return the countries whose name contains the search_value provided by the user.

laravel 5.2 work with belongs to with two different queries

I have write down this query
Controller
$data = User::where('name',$name)->with('country');
In User model
function country () {
return $this->belongsTo('App\Country');
}
In view
echo $data->country->name;
It is working fine but it run 2 queries :(
Select * from user where name = "xyz"
Select * from country where id = "745"
I want to stop this, I want to fetch data with one query only. Join is the solution, Is any other solution for this?
Unfortunately this is the way Eloquent works. It uses two queries because it's a simpler task to initialise your models and to avoid column naming conflicts.
If you are concerned about performance but still want some sort of querying tool, use the Query Builder shipped with Laravel.
To answer your question, joins will be your best bet.
$data=user::with('country')->where('id',745)->where('name','xyz')->get();
i hope that will help you

Resources