Technote

Performance optimization Advanced

Series Profiling WordPress performance Part 7 of 8

Autoloaded options: finding what rides on every request

Options marked autoload are read and unserialised on every request. One large blob quietly taxes the entire site, and nothing on screen says so.

At the start of every request WordPress reads every row in wp_options marked for autoload in a single query and holds it in memory. That is why option lookups are cheap — most options are already there.

The price of that design is exact: if a plugin stores a large value with autoload enabled, that value is read and unserialised even on requests that never use the feature. Nothing on screen mentions it and no particular page is slow, so it surfaces only as “everything feels slightly heavy”.

Get the list

Do not guess — measure. WP-CLI gives you the total and the biggest offenders separately.

# total autoloaded size
wp option list --autoload=on --format=total_bytes

# the twenty largest
wp option list --autoload=on --fields=option_name,size_bytes 
  --orderby=size_bytes --order=desc --format=table | head -20

Where CLI is unavailable, SQL answers the same question.

SELECT option_name, LENGTH(option_value) AS bytes
FROM wp_options
WHERE autoload IN ( 'yes', 'on', 'auto-on', 'auto' )
ORDER BY bytes DESC
LIMIT 20;

Recent core versions store autoload as more than a yes/no: there is an explicit setting and an automatic judgement, and options above a size threshold are excluded from autoloading for you. That judgement does not override a value a plugin set explicitly, which is why this remains something to watch.

What to look for in the top rows

What usually shows up at the top — only the last row belongs in autoload

Do not expect the object cache to solve this. With Redis in place the whole options bundle is cached, but if the bundle itself is large you still fetch and unserialise it every request. The cache moved the data; it did not make it smaller.

Fixing it — investigate before deleting

Finding the culprit is not permission to delete it. If code still writes that value it will be recreated on the next request and nothing has changed.

Four steps — skip the second and the same row grows straight back

Grepping the codebase for the option name usually finds the owner immediately. If it is dead weight, delete it; if it is used but not needed on every request, keep the value and drop the autoload flag.

# keep the value, stop autoloading it (recent core)
wp eval "wp_set_option_autoload( 'acme_big_blob', false );"

# on older core, rewrite it with the third argument set to false
wp eval "update_option( 'acme_big_blob', get_option( 'acme_big_blob' ), false );"

If a plugin keeps writing it back with autoload on, that is a defect on the plugin’s side. Report it to the author — and if nothing comes back, you now have one concrete reason to reconsider keeping it.

Finally, make this a recurring check. Autoload totals grow back as plugins are added, however thoroughly you clean up once. Continuous checking of that kind is what our InfraGuard passes cover, and related articles sit in the performance archive.

Next part

With the server side tidied, the last part is the browser. Next: a front-end budget — setting a ceiling on asset weight and actually holding it.

More on this topic

All technotes

Performance optimization Practical

A landing page speed audit you can run yourself

Asking engineering to "make it faster" gives nobody a task. Images, third-party scripts, fonts and the hero image are four things a marketer can check personally and hand…

Marketers 9 min read

Performance optimization Practical

Core Web Vitals in plain marketing language

Three metrics, three plain sentences: when does it appear, does it jump while loading, does it respond when tapped. Translate them and the request writes itself.

Marketers 7 min read

₩270,000 · Join the program