Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

hoangvnn's avatar

The query in the controller returns very slow results

After I checked mysql-slow.log, the results returned from the queries due to this controller are very slow (average takes about 58 seconds for a query). Please help me optimize these queries. The dev team has abandoned my project without support anymore, I'm really stuck.

public function topFavorite(Request $request)
	{
		$stories =  Story::select(['id', 'name', 'slug', 'source_id', 'status', 'author_id', 'total_words', 'view', 'cover', 'desc'])
			->with('author:id,name,slug')
			->withCount(['chapters' => function ($query) {
				$query->whereDate('publish_at', '<=', Carbon::now());
			}])
			->with('source:id,name,slug')->display()->get();
		$stories = $stories->sortByDesc('favorite')->values()->all();

		$currentPage = $request->page ?? 0;

		$perPage = $request->per_page ?? AppConst::DEFAULT_PER_PAGE;

		$currentItems = array_slice($stories, $perPage * ($currentPage  - 1), $perPage);
		$storiesPaginated = new LengthAwarePaginator($currentItems, count($stories),  $perPage, $currentPage);
		return response()->json($storiesPaginated);
	}

	public function recommendedNewestStories(Request $request)
	{
		$stories = Story::select(['id', 'name', 'slug', 'source_id', 'status', 'author_id', 'total_words', 'view', 'cover', 'desc'])->where('newest', true)
			->with('author:id,name,slug')
			->withCount(['chapters' => function ($query) {
				$query->whereDate('publish_at', '<=', Carbon::now());
			}])
			->with('source:id,name,slug')->display()
			->orderBy('created_at', 'desc')
			->paginate($request->per_page ?? AppConst::DEFAULT_PER_PAGE);
		return response()->json($stories);
	}

	// top story has most chapters in the month
	public function hasMostChaptersPm(Request $request)
	{
		$stories = Story::select(['id', 'name', 'slug', 'source_id', 'status', 'author_id', 'total_words', 'view', 'cover', 'desc'])->withCount(['chapters' => function ($query) {
			$query->whereDate('publish_at', '<=', Carbon::now()->whereDate('created_at', '>=', Carbon::now()->subMonth()));
		}])
			->with('author:id,name,slug')
			->with('source:id,name,slug')->display()
			->orderBy('chapters_count', 'desc')
			->paginate($request->per_page ?? AppConst::DEFAULT_PER_PAGE);
		return response()->json($stories);
	}


	// top story has most purchases in week
	public function topStoryPurchases(Request $request)
	{
		$stories = [];
		if(!Cache::has('topStoryInWeek_'.$request->page)){
			$perPage = $request->per_page ?? AppConst::DEFAULT_PER_PAGE;
			$results = Story::select(['id', 'name', 'slug', 'source_id', 'status', 'author_id', 'total_words', 'view', 'cover', 'desc'])->has('transactions')->withCount(['transactions' => function ($query) {
				$query->where('created_at', '>=', Carbon::now()->subWeek());
			}])
				->with('author:id,name,slug')
				->withCount(['chapters' => function ($query) {
					$query->whereDate('publish_at', '<=', Carbon::now());
				}])
				->with('source:id,name,slug')->display()
				->orderBy('transactions_count', 'desc')->take($perPage*5)->get();
				// ->paginate($request->per_page ?? AppConst::DEFAULT_PER_PAGE);
			$offset = 0;
			for($i=1; $i<=5; $i++){
                Cache::put('topStoryInWeek_'.$i, $results->slice($offset, $request->per_page), 4*3600);
                $offset += $request->per_page;
			}
            $stories = Cache::get('topStoryInWeek_'.$request->page);
		}
		else{
			$stories = Cache::get('topStoryInWeek_'.$request->page);
		}
		return response()->json($stories);
	}

	// Story newest
	public function stNewest(Request $request)
	{
		// Story newest
		$stories = Story::select(['id', 'name', 'slug', 'source_id', 'status', 'author_id', 'total_words', 'view', 'cover', 'desc'])->with('author:id,name,slug')->withCount(['chapters' => function ($query) {
			$query->whereDate('publish_at', '<=', Carbon::now());
		}])->with('source:id,name,slug')->display()
			->orderBy('created_at', 'DESC')
			->paginate($request->per_page ?? AppConst::DEFAULT_PER_PAGE);
		return response()->json($stories);
	}

	// Story by source
	public function stBySource(Request $request, Source $source)
	{
		$storiesQuery = Story::query();
		if ($source->id == 1) {
			$storiesQuery->withCount('transactions')->orderBy('transactions_count', 'desc');
		} else {
			$storiesQuery->orderBy('view', 'desc');
		}
		$stories = $storiesQuery->where('source_id', $source->id)
			->with('author:id,name,slug')
			->withCount(['chapters' => function ($query) {
				$query->whereDate('publish_at', '<=', Carbon::now());
			}])
			->with('source:id,name,slug')
			->display()
			->paginate($request->per_page ?? AppConst::DEFAULT_PER_PAGE, ['id', 'name', 'slug', 'source_id', 'status', 'author_id', 'total_words', 'view', 'cover', 'desc']);
		return response()->json($stories);
	}
	//story completed
	public function stCompleted(Request $request)
	{
		$stories = Story::select(['id', 'name', 'slug', 'source_id', 'status', 'author_id', 'total_words', 'view', 'cover', 'desc'])->where('status', true)->with('categories:id,name,slug')
			->with('author:id,name,slug')->withCount(['chapters' => function ($query) {
				$query->whereDate('publish_at', '<=', Carbon::now());
			}])->display()
			->with('source:id,name,slug')->orderBy('updated_at', 'desc')->paginate($request->per_page ?? AppConst::DEFAULT_PER_PAGE);
		return response()->json($stories);
	}

	// Story suggestion
	public function stSuggestion(Request $request, Story $story)
	{
		$categories = $story->categories;
		$categories = $categories->map(function ($item) {
			return   $item->id;
		});
		$stories = Story::select(['id', 'name', 'slug', 'source_id', 'status', 'author_id', 'total_words', 'view', 'cover', 'desc'])->with('author:id,name,slug')->withCount('transactions')
			->display()
			->orderBy('transactions_count', 'desc')->whereHas('categories', function (Builder $query) use ($categories) {
				$query->whereIn('category_id', $categories);
			})->take(10)->get();
		return response()->json($stories);
	}

	// Story editor choice
	public function stEditorChoice(Request $request)
	{
		// Story editor choice
		$stories = Story::select(['id', 'name', 'slug', 'source_id', 'status', 'author_id', 'total_words', 'view', 'cover', 'desc', 'editor_choice'])->where('editor_choice', true)
			->with('author:id,name,slug')
			->with('source:id,name,slug')
			->withCount(['chapters' => function ($query) {
				$query->whereDate('publish_at', '<=', Carbon::now());
			}])->display()
			->paginate($request->per_page ?? AppConst::DEFAULT_PER_PAGE);
		return response()->json($stories);
	}

	// Story hot
	public function stHot(Request $request)
	{
		// Story hot
		$stories = Story::select(['id', 'name', 'slug', 'source_id', 'status', 'author_id', 'total_words', 'view', 'cover', 'desc'])->has('transactions')->withCount('transactions')
			->with('author:id,name,slug')
			->with('source:id,name,slug')
			->withCount(['chapters' => function ($query) {
				$query->whereDate('publish_at', '<=', Carbon::now());
			}])->display()
			->orderBy('transactions_count', $request->order_by)
			->paginate($request->per_page ?? AppConst::DEFAULT_PER_PAGE);
		return response()->json($stories);
	}

mysql-slow.log:

select `id`, `name`, `slug`, `source_id`, `status`, `author_id`, `total_words`, `view`, `cover`, `desc`, (select count(*) from `transactions` where `stories`.`id` = `transactions`.`story_id`) as `transactions_count` from `stories` where `display` = 1 and exists (select * from `categories` inner join `story_categories` on `categories`.`id` = `story_categories`.`category_id` where `stories`.`id` = `story_categories`.`story_id` and `category_id` in (3, 31, 33, 64)) order by `transactions_count` desc limit 10;

Please help me. Thank you so much everyone

0 likes
2 replies
hoangvnn's avatar

@Snapey I have done index DB. However, the query time is still very slow, I realize maybe because the query is not optimized. From the query in mysql-slow.log I rewrote another query and tested it in phpMyadmin and found the response time to be very fast.

Please or to participate in this conversation.