Last week I literally had a dream about a way to improve performance in bbPress 2.6, and it worked better than I imagined. Here’s what I did, and how you might be able to do something similar.
TL;DR
Prime all the object caches.
WordPress is really smart. If you need to ask the database for something โ which is often a costly & slow transaction โ WordPress tries to avoid you needing to ask for the same thing again, at least until that thing changes.
It does this by saving the results in an internal cache, and it does this even if when a persistent cache engine is not available (see: Memcached or Redis.) It’s a clever (and obvious) way to do the right thing, and also be agnostic to the surrounding performance environment.
WordPress is also really simple. The majority of sites using it are of a traditional blog-style, where posts are looped-through and post authors are largely the same people across any given page or post.
Cardinality
bbPress (and subsequently BuddyPress also) are actually significantly different than WordPress, even though they use all the same code under the hood. Put simply, blogs are low cardinality, and forums & social networks are high. The object relationships, and the number of objects to relate, are just inherently higher when more people talk about more types of things in different types of ways.
For example, when viewing a blog post in WordPress, it will pre-fetch the post as part of the main query loop. Great – because everything coming next pertains to only that post (and maybe some sidebars and widget areas, too.)
Because you’ll be referencing this post a bunch of times, WordPress avoids repeated database hits.
But when you’re viewing a bbPress Topic, you’re actually looking at topic and its replies. The replies to that topic are likely from many different authors.
And when viewing a forum, topic-tag, or custom topic-view, you’re actually looking at both the thing being queried and the resulting topics from that thing in a loop.
And those topics also all have different authors. And the latest replies to all those topics are also different posts, each with their own authors…
Turtles all the way down ๐ข๐ข๐ข๐ข
Database Avoidance
The caching strategy inside of WordPress is really neat. It includes a helper function called _get_non_cached_ids()
ย to help avoid querying the database for things that are already in the cache, and bbPress can exploit the heck out of it to make things really, really speedy.
There are also 2 other really useful functions: _prime_post_caches()
ย and cache_users()
, and they use _get_non_cached_ids
ย to do pretty much what they say they do.
Given that bbPress has such a complex intersection of post types, statuses, ancestry, and authorship, it makes sense that WordPress is unprepared to prime all those caches for it, and so it does what it normally would and only queries for and caches what it needs to when it needs it, one-by-one, resulting in a bunch of round-trips to the database for each individual post & author.
WordPress doesn’t cache objects predictively or proactively, and that’s when I woke up from my 3am dream and started hacking on what was, admittedly, an embarrassing revelation of something I knew all along โ bbPress can be way better (BuddyPress, too!)
-60%
By looping through topics & replies, grabbing an array of child posts & their authors, then querying for them all at once, every single bbPress page sees about 60% fewer database queries. I had originally planned only on caching related posts, but pre-fetching post authors was just as easy and impressive.
The actual benefits depend on the intersection of authors & topics (that whole cardinality thing) but… it’s actually really amazing to see, for a few reasons I’ll try not to bore you with:
- This is such an obvious thing to do, I thought I already did it years ago. I’m an experienced developer, and I look for these things โ I just thought I solved this problem already.
- I (somewhat blindly) trusted that the caching strategy inside of WordPress was doing things the best way for reasons I hadn’t thought of, and I put off doing the deep-dive performance tuning.
- I couldn’t have proven my work without the help of the Query Monitor plugin by John Blackbourn. This plugin is interesting in that it will never have huge installation numbers (30k right now) because it’s a developer tool and isn’t really meant for production sites, but it’s literally the most important tool in any WordPress plugin developer’s belt.
ABC
Always. Be. Caching. While bbPress could have gotten this years ago, I’m happy it took this long to get here, because we’re able to guarantee the strategy is sound and correct for the future without having spent hours retuning around the ways bbPress evolved since 2010.
Props to my friends at Pagely and Pantheon who continue to support my work on WordPress related endeavors, and Matt for his continued trust. WordPress.org will directly benefit from these performance improvements, and obviously users of bbPress powered forums will too.
bbPress 2.6 is Release Candidate 5, and I’m excited for you to use it real soon. ๐