تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Identifying N+1 Issue0:00

Let's take a look at the AwardAchievements class. Now as you'll remember, this is an event listener. When a User earns experience, we want to award achievements to the User. So we get the User's achievements, and we sync them up with all of the achievements our system offers, filtered down to only those that the current User qualifies for. But now let's think. This is a little deceptive. We're grabbing our achievements out of the service container, and we register that here in the service provider, so AchievementServiceProvider. Now if I scroll down, it sounds like when we say within any file, App\Achievements,

in the service provider, so AchievementServiceProvider. Now if I scroll down, it sounds like when we say within any file, App, Achievements, well at least for the first call, we're going to hit this function here, where we collect all of the achievements in our system. So we're going to collect this big array, and for each one of those, we will new up the class. Now again, as you'll remember at the moment, in order to sync up each of these classes with a record in the database, that's the way we chose to tackle this, well, we're going to end up with an n plus one problem. Each time we instantiate one of these classes, we do a quick query to ensure that the necessary

Caching Achievements Singleton1:02

to end up with an n plus one problem. Each time we instantiate one of these classes, we do a quick query to ensure that the necessary record exists. But if you think about it, it's very, very rare that we will add more Achievements once we have the first batch in place. So I want to clean this up. I want to use caching instead. So if I switch to our ServiceProvider, when we resolve this out of the container, rather than doing this logic every single time, instead, we're going to do it a single time and then throw it into the cache.

than doing this logic every single time, instead, we're going to do it a single time and then throw it into the cache. So I'll say cache()->rememberForever('achievements'). And here we go. All right, so now I'm going to take all of that and paste it in. Now don't forget, we have to return something from the singleton. So we will return the results of this. Okay, so we're calling rememberForever because we can cache this as long as we possibly want. Again, it's very rarely going to change. All right, so now let's think.

First-Call Cache Behavior1:56

Again, it's very rarely going to change. All right, so now let's think. With our change, when we call app achievements, well, it's going to call this function. But on the very first call, like the very first person who hits this function, we're going to look in the cache. Do we have anything called achievements? No, there's nothing there. Okay, well, let's call this closure here, where we collect the achievement. We do run all of those database queries, but it only happens once. Then we return the result, and we cache the data as achievements.

Verifying Cache with Logs2:41

Let's go to our logs for August 7th. That's today. It's currently empty. However, once we resolve this out of the container, let's do this here. We'll say log info. Here I am. Just something to show that we are hitting this function. And if we do hit this log here, that means we are running all of those database queries. Okay, so if we now, I'm just going to switch to a page. If we now trigger some activity that generates new experience, like completing a lesson,

Okay, so if we now, I'm just going to switch to a page. If we now trigger some activity that generates new experience, like completing a lesson, well, if I switch back and we go to our log file, sure enough, we see that log here. So let's do it again. So let's generate more experience, basically do it all over again. And if I switch back, I don't get another log, and that's because it has been thrown in the cache. Let's look for it. php artisan tinker, cache, get achievements. And sure enough, we see our collection of achievements.

Clearing Cache Safely3:27

php artisan tinker, cache, get achievements. And sure enough, we see our collection of achievements. So now at this point, whenever we generate a new achievement, all we need to do is manually clear this key from the cache, and we're good to go. Now be careful, don't do something like this, where your first instinct might be to say, well, when you generate a new achievement, we'll just add that step down here. We'll say cache, forget achievements. And you'll think, oh yeah, that'll do the trick, and you test it locally and it works. But don't forget, this is going to be happening on production, right? So you would generate a new achievement locally.

But don't forget, this is going to be happening on production, right? So you would generate a new Achievement locally. And yes, it'll clear the cache locally, but that has nothing to do with your production cache. So you could add a custom command if you want to do this, or sometimes for things like this where it so rarely changes, just do it manually. In my production DB, I will boot up php artisan tinker, and then I will run that here. It's up to you. Nonetheless, now the important thing to remember is, when we resolve achievements out of the service container, only on that very first occurrence by any user, the very first occurrence,

Nonetheless, now the important thing to remember is, when we resolve achievements out of the service container, only on that very first occurrence by any user, the very first occurrence, will we perform those database queries. And after that, they all get thrown into the DB until it's time to add a new achievement.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟