oma

TTFB extremely slow... caching options discussion

Recommended Posts

Hi everyone

I’m super close on launching a site I have been working on for a while but upon some final testing the TTFB on the site is super slow... like 6s slow which is madness.

The site uses a lot of page queries and includes but apart from that it’s generally pretty fast – the load times after TTFB are fine.

I’m wondering about a few things...

1. ProCache – this works amazingly well when enabled but of course each page has to be cached first and if the TTFB on each is slow then do you think it’s a redundant move? Is there a way to cache the pages without visiting each one? And do you think if a page is saved the default should be to empty the cache for the whole site? Be nice to get some feelings on best practice for this.

2. I use a lot of includes (.inc) in my templates as I try to build everything quite modular. Is there a better way to do this (render?) or is this generally fine?

3. Template cache – would this help with TTFB or rather the issue is with the MySQL pages queries so template caching wouldn’t help with this. I’m a little confused on template caching...

3. Markup cache – could this be used for improving TTFB DB queries or not?

Thanks everyone... just keen for a bit of discussion and best practice on this.

Share this post


Link to post
Share on other sites

What's the TTFB of a procached version of a page X (a complex one)?

I think template cache will not get you any advantage over ProCache, but MarkupCache will as you can cache parts of the page before ProCache kicks in! 

Use markup cache for blocks of code that do complex queries or when querying multiple pages.

Basic example: A website has hundreds of podcast episodes. You can cache a count of these episodes so you don't need to query it when the page cache is cleared in ProCache.

$template = $templates->get("podcasts"); //episodes
$all_episodes_count = $cache->get("all_episodes_count", $template, function($page) {
  return $page->NumChildren(true);
});
$view->total_episodes = $all_episodes_count;

The "all_episodes_count" cache file will only be cleared when a new page is created with the template "podcasts".

 

  • Like 2

Share this post


Link to post
Share on other sites
6 hours ago, Sergio said:

What's the TTFB of a procached version of a page X (a complex one)?

81ms :)

6 hours ago, Sergio said:

Use markup cache for blocks of code that do complex queries or when querying multiple pages.

Ah yes I was reading about WireCache... is it possible to declare more than one template in the get statement?

$template = $templates->get("events-detail|guides-detail"); // But this of course only grabs the first
$articles = $cache->get("wtg", $template, function($pages) {
	return $pages->find("template=events-detail|guides-detail, sort=sort");
});

Thanks for your help!

Share this post


Link to post
Share on other sites

Also this seems to be working but is this all correct?

	$eventsDetailTemplate = $templates->get("events-detail");
	$wtgDetailTemplate = $templates->get("where-to-go-detail");
	$mtlDetailTemplate = $templates->get("meet-the-locals-detail");

	$related_events = $cache->get("relatedEvents", $eventsDetailTemplate, function($pages, $page) {
		return $pages->find("template=events-detail, id!=$page, location_venue!=$page, tags=$page->tags, events_detail_dates_final_date>=today, sort=random");
	});

	$related_wtg = $cache->get("relatedWTG", $wtgDetailTemplate, function($pages, $page) {
		return $pages->find("template=where-to-go-detail, id!=$page, tags=$page->tags, sort=random");
	});

	$related_mtl = $cache->get("relatedMTL", $mtlDetailTemplate, function($pages, $page) {
		return $pages->find("template=meet-the-locals-detail, id!=$page, tags=$page->tags, sort=random");
	});

	$related = $related_events->import($related_wtg)->import($related_mtl);
	$related->sort('random')->filter("limit=4");

 

Share this post


Link to post
Share on other sites
Posted (edited)
13 hours ago, oma said:

The site uses a lot of page queries

It's this part that probably has the most impact on performance.

 

1 hour ago, oma said:

Also this seems to be working but is this all correct?


	$eventsDetailTemplate = $templates->get("events-detail");
	$wtgDetailTemplate = $templates->get("where-to-go-detail");
	$mtlDetailTemplate = $templates->get("meet-the-locals-detail");

	$related_events = $cache->get("relatedEvents", $eventsDetailTemplate, function($pages, $page) {
		return $pages->find("template=events-detail, id!=$page, location_venue!=$page, tags=$page->tags, events_detail_dates_final_date>=today, sort=random");
	});

	$related_wtg = $cache->get("relatedWTG", $wtgDetailTemplate, function($pages, $page) {
		return $pages->find("template=where-to-go-detail, id!=$page, tags=$page->tags, sort=random");
	});

	$related_mtl = $cache->get("relatedMTL", $mtlDetailTemplate, function($pages, $page) {
		return $pages->find("template=meet-the-locals-detail, id!=$page, tags=$page->tags, sort=random");
	});

	$related = $related_events->import($related_wtg)->import($related_mtl);
	$related->sort('random')->filter("limit=4");

 

If that is just to find four random items it could be done a lot more efficiently as:

$related = $pages->find("id!=$page, tags=$page->tags, (template=where-to-go-detail|meet-the-locals-detail), (template=events-detail, location_venue!=$page, events_detail_dates_final_date>=today), sort=random, limit=4");

When you are wanting a specific number of results, wherever possible you should do that via a limit in the database query i.e. in the $pages->find() selector.

Edited by Robin S
Corrected $pages typo.
  • Like 3

Share this post


Link to post
Share on other sites

Thanks for your help, everyone.

ProCache is working pretty well – it's just that initial load per page (before it's cached) that's causing me a few problems as that initial load is slow.

I have about 3 $pages->find() queries on one of my pages where the initial load is slow – each of them querying about 150 pages. This would cause such slow initial load, right?

Share this post


Link to post
Share on other sites

Also if anyone has any suggestions on how to use WireCache $cache with multiple templates?

$articles = $pages->find("template=where-to-go-detail|our-guides-detail, sort=sort");

The below doesn't work and returns the following error (which I guess is because I'm using $templates->find() rather than $templates->get() and the $cache expected a single template?

PHP Notice: Object of class ProcessWire\TemplatesArray could not be converted to int in

$template = $templates->find("name=where-to-go-detail|our-guides-detail");
$articles = $cache->get("wtg", $template, function($pages) {
    return $pages->find("template=where-to-go-detail|our-guides-detail, sort=sort");
});

Share this post


Link to post
Share on other sites
53 minutes ago, oma said:

Also if anyone has any suggestions on how to use WireCache $cache with multiple templates

I never used this approach for more than one template, but you can also use the $expire parameter:

    $all_matches = $cache->save('all_articles', $pages->find("template=where-to-go-detail|our-guides-detail, sort=sort"), $expire = 432000); //week

 

Share this post


Link to post
Share on other sites
5 minutes ago, Sergio said:

I never used this approach for more than one template, but you can also use the $expire parameter:

Thanks, Sergio but I was wanting to do a check if a page using either the template where-to-go-detail or our-guides-detail is updated to reset the cache... whereas you can seem to only check one template.

Share this post


Link to post
Share on other sites
8 hours ago, oma said:

I was wanting to do a check if a page using either the template where-to-go-detail or our-guides-detail is updated to reset the cache

See this blog post where it talks about using a selector string as the "expires" argument.

But before you go too far into WireCache as a solution for your problem I recommend going through your PageFinder queries ($pages->find(), $page->children(), etc) to see if they can be optimised. You might find you don't need WireCache then - for example, if you change to the query I suggested in my previous post you probably wouldn't need to cache it.

9 hours ago, oma said:

I have about 3 $pages->find() queries on one of my pages where the initial load is slow – each of them querying about 150 pages.

It's not so much how many pages you are querying that matters, it's how many pages your query is returning. If each of your 3 queries returns 150 pages then this is not ideal unless you are actually using 450 pages in your markup somehow. Your aim should be to return no more pages that you are actually going to use. Also try to avoid multiple PageFinder queries if the same result can be achieved in one query (as demonstrated in my previous post).

 

Share this post


Link to post
Share on other sites

Thanks for this, Robin.

One query is returning 60+ results... no pagination. As soon as I add a limit to it (18) it’s a lot faster. Guess that’s mainly it, right? Interesting to know re the wireCache... but apart from the odd few queries that I will make more efficient I guess it’s down to what’s being returned (rather than queried as you say).

Share this post


Link to post
Share on other sites
12 hours ago, oma said:

Thanks, Sergio but I was wanting to do a check if a page using either the template where-to-go-detail or our-guides-detail is updated to reset the cache... whereas you can seem to only check one template.

You can use a hook in ready.php to delete cache on save of pages

// delete caches when pages are created, saved or moved around
wire()->addHookAfter('Pages::save', function(Hookevent $event) {

  $page = $event->arguments(0);
  // do nothing on admin pages
  if($page->template == 'admin') return;
  
  // delete cache for templates  
  if($page->template == 'where-to-go-detail' || $page->template == 'our-guides-detail') {
    $this->cache->delete('wtg');
    // here you could add logic to rebuild the cache
  }
  
});

 

  • Like 5

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Recently Browsing   0 members

    No registered users viewing this page.