Technote

Performance optimization Practical

Series Profiling WordPress performance Part 4 of 8

The object cache: what Redis actually removes

Repeated identical lookups disappear. One slow query does not. Miss that distinction and you will wire up Redis and then ask why nothing got faster.

WordPress ships with an object cache by default. Options, posts, meta and term lookups all pass through it, so reading the same value ten times in one request hits the database once. The default implementation, though, disappears when the request ends — it lives only in that PHP process’s memory.

Adding a persistent backend such as Redis does exactly one thing: it keeps that cache alive between requests. That is the whole change, which is why what improves and what stays the same is entirely predictable.

What it removes, and what it does not

A cache removes repetition; it does not shorten a single expensive operation

The first line on the left is the point. Put a cache in front of a four-second query and things improve from the second request onwards. The first one still costs four seconds, and so does the next one after every expiry or invalidation. This is where the slow-versus-duplicated distinction pays off: duplication disappears with a cache; a slow query has to be fixed.

On the right, the entry worth noticing is logged-in screens. Authenticated requests bypass the page cache and therefore always execute PHP, and that is exactly the path where an object cache earns its keep. It is why complaints about a heavy admin often change character once this layer exists.

Checks after wiring it up

Start by confirming the drop-in is valid and the connection is live. WP-CLI is the quickest route.

wp redis status
wp cache flush        # once after a deploy, so stale structures do not linger

Then watch the hit rate. A persistently low one means either that something keeps flushing the cache, or that your keys differ on every request so nothing is ever reused. The latter happens when code mixes a timestamp or a random value into the key.

When you use the cache directly, distinguish a miss from a stored false. The fourth argument tells you which you got.

$value = wp_cache_get( 'acme_report', 'acme', false, $found );

if ( ! $found ) {
    $value = acme_build_report();                 // the expensive part still runs once here
    wp_cache_set( 'acme_report', $value, 'acme', 300 );
}

Testing only false === $value cannot tell a genuine false from a miss, so the value gets recomputed on every request. It is the first code to suspect when a hit rate looks inexplicably poor.

Groups that should not persist

Not every value deserves to outlive the request. Intermediate results and per-request counters pushed into Redis only add round trips, and can introduce consistency problems of their own.

wp_cache_add_non_persistent_groups( [ 'acme_runtime' ] );

Declare that as the plugin loads. Conversely, if several sites share one Redis instance, separate them by key prefix and database index so they cannot overwrite each other — a mistake local development environments produce regularly.

Cache layering is covered further in the servers and infrastructure archive, and introducing and verifying Redis is part of the scope of our optimization program.

Next part

Core fills and clears the object cache for you. A cache you write yourself comes with the clearing as your responsibility — next up, transients and invalidation design.

More on this topic

All technotes

Performance optimization Practical

Who pays for the milliseconds a tag adds?

A tracking script does not stop at downloading. While it is parsed and executed the main thread is busy, and a busy page ignores fingers. That cost is…

Marketers 5 min read

Performance optimization Practical

This is how a landing page gets heavy

Nobody decides to make a landing page heavy. It accumulates: one addition per campaign, and nothing ever removed when the campaign ends.

Marketers 6 min read

Performance optimization Practical

The N+1 problem: get_post_meta in a loop, and priming

WP_Query primes caches for its own results only. A hand-built list of IDs gets none of that for free — and that difference decides your query count.

Developers 7 min read

₩270,000 · Join the program