简体   繁体   中英

Laravel - How many queries is too many?

I have a laravel website that lists "submissions" much like reddit. I use this example to more easily understand this problem.

在此处输入图片说明 When a user visits the home page, for example, he'll see 30 submissions listed.

Each submission represents a lot of information. Sure there's information from the submission itself, like the title and whatnot. But there's things like "save". For each submission, there must be a query to see if that user hasn't saved the submission, or else it would display "unsave".

Blade:

@if (!Auth::user()->hasSavedSubmission($submission))
    <a href="{{ route('save.submission', ['ID' => $submission->id, 'token' => $submission->token]) }}">Save</a>
@else
    <a href="{{ route('unsave.submission', ['ID' => $submission->id, 'token' => $submission->token]) }}">Unsave</a>                     
@endif

User Model:

 public function hasSavedSubmission(Submission $submission) {
    return (bool) $submission->savedSubmissions->where('user_id', $this->id)->count();
}   

Which then requires a query. But there isn't just hasSavedSubmission , there's a query to see if the user has upvoted/downvoted a submission, or whether or not they've subscribed to that sub, etc..

It gets even worse on comment pages. Let's say I load a comments page with 200 comments. Well, to see if you've saved a comment or voted on a comment, that's 2 queries per comment, making it a total of 400 queries.

Is this normal? Is this good practice, or should I be optimizing this somehow to reduce queries, and how?

A lot of queries are not bad per se, but in your case they can be reduced greatly by adjusting the way you query your database. Currently you query the saved submissions for a each submission seperately, you could alter it so you'll retrieve all saved submissions for a user in just one query.

As an example you could do something like this in your controller:

$query = SavedSubmissions::where('user_id', Auth::user()->id);
$submissionsForUser = $query->get('id'); // only load columns you'll need also saves a bit
// Pass $submissionsForUser to your blade template

In your blade template

@if (!submissionsForUser->contains($submission->id)
    <a href="{{ route('save.submission', ['ID' => $submission->id, 'token' => $submission->token]) }}">Save</a>
@else
    <a href="{{ route('unsave.submission', ['ID' => $submission->id, 'token' => $submission->token]) }}">Unsave</a>                     
@endif

Alternativly you could move this logic for retrieving the submissions to the User model, but that's not very clean.

Other ways to reduce the amount of queries are things like:

  • Paginating the amount of comments
  • Lazy-loading comments (only show the first few, with a 'more' button)
  • Adjusting your database schema so you'll have denormalized data for specific views (eg 1 table contains all data for 1 view)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM