minaremonshaker's avatar

Unexpected Slow Performance Despite Caching and Optimization

I have a users table containing only five records. When retrieving these users from the database using a standard query, the request takes about 2642 ms. However, even when fetching the same data from cache, it still takes around 1977 ms. I’m unsure why this happens.

I have already applied several optimizations, including running php artisan optimize:clear, caching query results, and switching the session and caching drivers to Redis. Despite these efforts, the performance issue remains.

You can find the relevant code for UsersService, UsersController, and UserHandlerTrait in the link below: https://gist.github.com/mina20088/3aaf5a83dc9411bcfec1f14812a759ff

Note: UserHandlerTrait acts as a layer between the service and controller to keep the controller lightweight. and i have debug enabled in my .env also i have clockwork

0 likes
30 replies
Tray2's avatar

Sounds to me that you either have a very poorly written SQL query, or there is an issue with the database, or you have a faulty setup somewhere in your infra structure.

I would suggest installing the Laravel debugbar, or Clockwork to narrow it down a bit, to see where the actual bottle neck is.

I would also like to point out that you have written a shitload of code for something as simple as listing users. I suggest that you in your controller just do.

public function index()
{
	return view('users.index')
		->with([
			'users' => User::orderBy('name')
					->paginate(20)
	]);
}

If it's still is slow, then it's most likely something with server setup.

I recommend using KISS, rather than the complex pattern you are using.

If you want filtering capabilities you can do something like this.

return view('books.index')
            ->with([
                'books' => BookIndexView::query()
                    ->when($request['authors'], function ($query, $authors) {
                        $query->whereIn('author_id',
                            $this->numericStringToArray($authors));
                    })
                    ->when($request['published'], function ($query, $published) {
                        $query->where('published_year', $published);
                    })
                    ->when($request['genre'], function ($query, $genre) {
                        $query->where('genre', $genre);
                    })
                    ->when($request['format'], function ($query, $format) {
                        $query->where('format', $format);
                    })
                    ->when($request['search'], function ($query, $search) {
                        $query->where('title', 'LIKE',  "%$search%")
                        ->orWhere('author_name', 'LIKE', "%$search%")
                        ->orWhere('series', 'LIKE', "%$search%");
                    })
                    ->orderBy('author_name')
                    ->orderBy('series')
                    ->orderBy('part')
                    ->orderBy('published_year')
                    ->get(),
            ]);
```

1 like
minaremonshaker's avatar

I’d like to clarify that the functionality extends far beyond simply listing users. It also covers searching, ordering, filtering by different criteria like gender, and pagination, among other advanced features. If all of this logic is put directly in the controller, it can quickly become very large. While you prefer the KISS approach, my preference is to keep the controller as small as possible and abstract logic behind the scenes. That doesn't mean your approach is incorrect—it just comes down to personal preference. Also, after checking with Clockwork, the queries themselves are not the problem. But any ways I will try this approach to examine the performance an I will send you you here

Tray2's avatar

Sure but there are things in your code that can be yanked out.

In your store method you use a FormRequest, which is good.

 public function store(StoreUserRequest $request, UsersService $service): RedirectResponse
    {
        $user = $this->initialize($service,$request)->createUser( $request->validated());

        return redirect()->route('dashboard.users')->with('success', __('messages.user.success', ['id' =>  $user->id ]))    ;
    }

You pass the validated array to the createUserMethod, then in the createUser method you assign the separate values in the array to another array.

 $user = $this->usersService->createUser([
            'first_name' => $validated['first_name'],
            'last_name' => $validated['last_name'],
            'username' => $validated['username'],
            'email' => $validated['email'],
            'password' => $validated['password'],
        ]);

You should be able to change that to simply be

$user = $this->userService->createUser($validated);

If you have set your $fillable array then it will remove all the unwanted fields for the model.

Glukinho's avatar

Go to php artisan tinker and measure how long it takes to fetch all users with simple Users::all() and your UserService, and compare.

If simple fetching is fast while your UserService is slow then the problem is in your complicated code.

If they are equally slow then the problem is in your server or database or network (if database is on remote host).

minaremonshaker's avatar

why all of you say that the code is complicated while its consists of three parts first a service which has the business logic second is the controller handle request between them there are a layer trait to make the controller smaller , also i just cutted the ->when () into smaller parts function for make things easy

Glukinho's avatar

I don't blame your code, I just suggest measuring and testing to locate the problem.

Sinnbeck's avatar

You need to do some debugging here. Return just the users with User::all(). If that is also slow, you have some issues with your database set up. If it's slow to return a view without queries, it's nothing to do with the queries at all

Sinnbeck's avatar

So User::all() is just as slow? What about another model? Same issue?

Sinnbeck's avatar

Ok I feel you aren't really answering if a simple query is just as slow. Is this slow?

Route::get('test', function () {
    return User::all();
} 
Sinnbeck's avatar

Then the issues has nothing to do with the code you posted. Either the connection to the database or something elsewhere in your app. Do you have DB::listen() anywhere?

Is it slow if you do DB::table('users')->get()?

If that is also slow, is the database on an external server?

minaremonshaker's avatar

i have tried User::paginate() because i have pagination and if i tried ->get() app craches , and no i dont have this db::listen() in my code , i will try this DB::table() and give you feedback

Sinnbeck's avatar

Ok so everything related to the database. Seems like that is what you need to debug.

Perhaps start by explaining your setup

minaremonshaker's avatar

"Hi, I’m using Laragon on Windows 11 with phpMyAdmin, along with Redis for caching and session management. Is there any other information you need?"

Tray2's avatar

Window 11 is really bad att this in the never patches, I would suggest that you use wls2 or use a proper linux install on you machine/docker/vm.

JussiMannisto's avatar

How do you measure the delay? If you just measure network response times, it might be something other than the DB connection. Earlier you mentioned that fetching cached data is also slow, which leads me to think it's something else, since you're not using database for sessions or cache.

You haven't replied to this question: are the responses slow when you have no database queries? You can test it by returning an empty view.

You can also run the query directly in Tinker to see if the issue is with your DB connection. Or you can install Debugbar, as has been suggested, to see which part of the request causes the delay.

minaremonshaker's avatar

I get numbers above from clockwork debugger ,but let me check the empty view an give you feedback

minaremonshaker's avatar

i have a controller that return view home as below , the view extends app layout only and has no content empty view , from clockwork i have response time 2749 ms no database connection in this page , unfortunately i cant add a screenshot in here but if you have a way that i can do that to send you a screen shoot till me

    public function home(){
        return view("home");
    }
Glukinho's avatar

Try to disable Windows Defender (and any other anti_virus software in case you have one), reboot the PC and check again.

1 like
minaremonshaker's avatar

i have tried all of the troubleshooting but still the same , i will try to make a new project in laragon and move the data in it may be there are somthig wrong in my setup

minaremonshaker's avatar

I'm not sure what exactly the problem is. I created a new project, but the welcome page loads slowly — it takes about 1.62 seconds. Could this be related to my Windows setup or my laptop hardware? I’m using a Dell Precision 5520 with an i7 HQ processor and 16 GB of RAM. I also noticed something in the browser’s developer tools — under the Network tab, in the Timing section, it shows "Application -> 1.14s." Does this information help?

minaremonshaker's avatar

Hi, I used the Clockwork profiler to trace the source of the issue, and it revealed that the main bottleneck is the internal function php::curl_exec, which took 1031.1 ms to execute. The next slowest function was Composer\Autoload{closure:C\laragon\www\blog\vendor\composer\ClassLoader.php:575-577}, taking 408.9 ms. After identifying the cause, I stopped Laradumps, which uses curl by default to send data to its desktop application. Additionally, I fixed a class whose name didn’t comply with PSR-4 conventions in ClassLoader.php. These changes reduced the overall response time to 715 ms.

minaremonshaker's avatar

Yes, this was one of the troubleshooting steps I tried, but after reviewing the two issues mentioned above and following their steps, I found the main problem was with LaraDumps, which uses cURL by default. I changed its configuration, specifically the dispatcher option from curl to tcp, and this significantly reduced the response time according to the profiler.

Please or to participate in this conversation.