Jump to content

Cache options


muzzer
 Share

Recommended Posts

Thought I would share the following experience here for anyone interested in caching in PW.

Converting a site from modx (Evo) to PW and finding some interesting performance issues.

One page which pulls in content from 50 other pages ran really well under modx, page load (uncached) was around 450ms (yeah, not that fast but a lot of database action and formatting happening there). Converted the site to to PW and it took a massive hit, loading in around 3200ms. I was surprised as I always though PW was supposed to be lightning fast. It's possible (probable?) I'm doing something with $pages which is not well optimized, not sure at this stage but will look more into this when I get a moment.

Anyway, I found two parts which were taking the longest to process and coded MarkupCache to these areas. Never used it before but found it very easy and nice to work with and just works beautifully, superb, all credit to the developer. The result of this quick bit of optimising was a page load speed reduced from 3200 to around 600ms. Impressive. And so easy to manage.

While on the topic; There are several options for caching in PW, including template caching, markupcache, and procache. There's bit's and pieces on the forums about each, but is there a writeup somewhere summarising pros and cons of each? I was thinking of trying out template caching or even better ProCache but the site is probably too dynamic. Analytics, counters, live stats on the pages, etc. so I'm thinking it will be not so good yeah? Any advice welcome.  :)

Link to comment
Share on other sites

Okay, I've done some timing tests and am amazed at the speed PHP logic is processed. Not that that's relevant in the case. The parts that are slowing the page down are the retrieval of PW page fields. I will abbreviate;
 
The site lists accommodation houses. The page I'm testing has brief listing info on 52 houses (I know, I could/should paginate but don't want to in this case). Each brief listing echos out or tests about 30 fields from a PW page.  So (simplified) for each of the 52 listings:

function generateListing( $id )
   {
      $html = '';
      $page = wire('pages')->get('/listings/')->find('listingId='.$id )->first();

      $html .= $page->listingName;
      $html .= $page->postalAddress;
      if( $page->streetAddress=='')
         $html .= $page->streetAddress;
      // and a heap more of these type of statements with various formatting/logic

      return $html;
   }

Each $page->field request timed as follows....

   $t = microtime();
   $html .= $page->streetAddress;
   debug(microtime()-$t); 

.... comes in at approx 0.0015sec (1.5ms).

Doesn't sound like much but do this 30 times for each listing and then 50 listings = 30 * 50 * 0.0015 = 2.25 seconds = sluggish.

So I'm assuming the 0.0015sec must represents a mySQL query - are the field queries done as required rather than when the $page object is created? If so, is there any way quickly query all page fields into an array in one swoop?

I'm guessing the reason modx is so much quicker in this case is because all the fields are in one table, so one "select" query pulls all 30 fields into a PHP array, whereas with PW I guess there are 30 separate queries happening here, one for each field?

Link to comment
Share on other sites

@muzzer: most fields (almost all of them) are only loaded as required. You can check "Autoload" within field settings (Advanced tab) to always include it with the page, though. This makes sense especially if that field is always used when the page is loaded.

You should also take a look at built-in Fieldtype Cache too; sounds like it could be exactly what you're looking for here. It's a core module but not installed by default.

I wrote a quick post about caching in ProcessWire a while ago, you can find it here. It's not too in-depth (and doesn't mention aforementioned Fieldtype Cache at all), so I'm not sure if it provides you any new information at all :)

  • Like 3
Link to comment
Share on other sites

I'm not sure I understand your structure, but I think the query could be optimized.

Couldn't you get all the listings with one query, something like this:

$listings = wire('pages')->find("template=listing,parent=/listings/");

// Then pass the page directly in your function, no need to call find() again in the function
foreach ($listings as $listing) {
  echo generateListing($listing);
}
  • Like 6
Link to comment
Share on other sites

@teppo I read your post a while ago but could not remember where to find it again so thanks for that, very nice writeup on caching and also good info there on hooks too for anyone looking for a clear explanation on this. Nice.

I'll look into fieldtype caching. There does not seem to be much mention of it anywhere - googling it only returns a few vague bit and pieces (expect your own post here, which gives a pretty good overview of it I think). I'll give it a tryout anyway, sounds like it might be an option.

@wanze Thanks for this suggestion. You are right, I'm calling find twice which is stupid so I'll definately alter this. The timing tests I did showed the sluggishness was due to the actual retrieval of individual field data rather than the fetching of the page objects (which was fast) so I don't expect it to make a huge difference, but any parts which can be optimized I'll look at, so this is a helpful suggestion.  :) 

  • Like 1
Link to comment
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
 Share

×
×
  • Create New...