Table of content
- Why the Database Is Usually the Bottleneck Nobody Fixes
- Step 1: Measure Database Load Before Touching Anything
- Step 2: Audit Autoloaded Data in wp_options
- Step 3: Clean Up Post Revisions, Drafts, and Orphaned Meta
- Step 4: Optimize and Repair Tables
- Step 5: Manage Transients Properly
- Step 6: Audit and Index Key Query Patterns
- Step 7: Address WooCommerce-Specific Table Growth
- Step 8: Implement a Recurring Database Maintenance Schedule
- Frequently Asked Questions
Why the Database Is Usually the Bottleneck Nobody Fixes
Most WordPress performance conversations start with caching, image compression, or CDN setup. Those matter — but agencies that run sites at scale consistently hit a wall that no cache plugin can solve: a bloated, unoptimized database. A well-structured WordPress database performance checklist addresses the layer that sits beneath every page request, especially for WooCommerce stores, membership sites, and any WordPress install that has been live for more than 12 months.
According to MySQL documentation, table fragmentation alone can increase query execution time by 20–40% on heavily written tables — and WordPress writes constantly: posts, options, transients, sessions, revisions. Without a systematic approach to database health, you are shipping performance problems to production whether you realize it or not.
This guide covers the full checklist — not just the cosmetic cleanup steps, but the structural and diagnostic layers that most tutorials skip.
Step 1: Measure Database Load Before Touching Anything
The cardinal rule of any performance work: measure first. Before running any optimization routine, you need a baseline that tells you where the problem actually lives.
Tools worth using
- Query Monitor plugin — shows every database query per page load, including caller, execution time, and whether the query is a duplicate. Install it, load a representative page, and sort by query time. This is the fastest way to find expensive queries.
- New Relic or Datadog APM — for production environments where you cannot run debug plugins, application performance monitoring shows database response times as a percentage of total server time. If DB time is above 30–40% of total response time, you have a database problem, not a code problem.
- MySQL slow query log — enable it at the server level with a threshold of 1–2 seconds. Review the log after 24–48 hours of real traffic. Slow queries that appear repeatedly are your highest-priority targets.
Do not skip this step. Optimizing tables you do not use wastes time. Measuring first means your efforts are targeted.
Step 2: Audit Autoloaded Data in wp_options
The wp_options table is loaded on virtually every WordPress page request. WordPress loads all rows where autoload = yes into memory on initialization. In a healthy site, this payload should be under 1MB. On sites that have accumulated plugins for years, it commonly reaches 5–15MB — loaded on every single request, even ones that do not need that data.
How to audit autoloaded data
Run this SQL query directly in phpMyAdmin or via WP-CLI:
SELECT option_name, length(option_value) AS size
FROM wp_options
WHERE autoload = 'yes'
ORDER BY size DESC
LIMIT 30;
Review the top offenders. Common culprits include:
- Transients that were never cleaned up after plugin removal
- Serialized plugin configuration objects from deactivated plugins
- Analytics or tracking scripts that store large data sets in options
- Session data that should be stored in a dedicated table or external cache
For rows that belong to inactive plugins, delete them. For rows that are legitimately needed but bloated, consider whether that data should be autoloaded at all — many plugin developers set autoload to yes by default when off would be more appropriate.
Step 3: Clean Up Post Revisions, Drafts, and Orphaned Meta
WordPress saves a revision every time a post is updated. On an editorial-heavy site, a single post can accumulate 50–100 revisions. Multiply that across hundreds of posts and the wp_posts and wp_postmeta tables become significantly larger than they need to be — with no user-facing benefit.
Revision management

Add this to wp-config.php to cap revisions going forward:
define('WP_POST_REVISIONS', 5);
For existing revisions, use WP-CLI to delete them in batches without locking the database:
wp post delete $(wp post list --post_type=revision --format=ids) --force
Run this during low-traffic hours. Deleting thousands of rows at once on a live site can trigger table locks.
Orphaned post meta
When posts are deleted, their associated postmeta rows are not always cleaned up. This query finds orphaned meta:
SELECT pm.meta_id FROM wp_postmeta pm
LEFT JOIN wp_posts p ON p.ID = pm.post_id
WHERE p.ID IS NULL;
Orphaned meta does not affect query performance as dramatically as autoloaded options, but it contributes to table size and backup bloat — both real operational costs for agencies managing dozens of client sites.
Step 4: Optimize and Repair Tables
MySQL tables accumulate fragmentation over time, particularly in tables with frequent inserts and deletes like wp_options, wp_comments, and WooCommerce order tables. Fragmentation means the storage engine has to read more physical disk blocks to return the same data — which increases I/O and slows queries.
You can optimize all tables via WP-CLI:
wp db optimize
Or target specific tables in MySQL:
OPTIMIZE TABLE wp_options, wp_posts, wp_postmeta;
On InnoDB tables (which is the default engine for most modern WordPress installs), OPTIMIZE TABLE rebuilds the table and its indexes — reclaiming space and defragmenting. For large tables, this can be a significant operation. Run it during a maintenance window or use the pt-online-schema-change tool from Percona for zero-downtime optimization on high-traffic production sites.
Step 5: Manage Transients Properly
Transients are WordPress’s built-in caching API for database-stored temporary data. Used correctly, they reduce expensive external API calls. Used carelessly, they become junk data that clogs the wp_options table with expired records that WordPress does not aggressively clean up.
Two scenarios to watch for
Expired transients not being deleted: WordPress only deletes expired transients when they are accessed — not on a schedule. If a transient is set but never requested again, it sits in the database indefinitely. On a site with many plugin integrations, this accumulates quickly.
Transients bypassed by object caching: If your server runs Redis or Memcached with a persistent object cache, WordPress stores transients in memory instead of the database. This is the correct approach at scale. If you are not using a persistent object cache, transients in the database are a known limitation of the architecture — and cleaning them up becomes part of your maintenance routine.
Use this WP-CLI command to delete expired transients:
wp transient delete --expired
Add this to a weekly cron job on client sites. It takes seconds to run and prevents gradual accumulation.
Step 6: Audit and Index Key Query Patterns
This is the step that separates a superficial cleanup from a genuine database performance audit. Missing database indexes mean WordPress — or your custom code — is running full table scans instead of indexed lookups. On a table with 100,000 rows, the difference between an indexed query and a full scan can be three orders of magnitude in execution time.
Common missing index scenarios in WordPress
- Custom post type queries with meta_key filters: Queries that filter by
meta_keyANDmeta_valuetogether often benefit from a composite index. WordPress adds individual indexes onmeta_keyandmeta_valuebut not composite indexes for custom query patterns. - WooCommerce order queries by status and date: High-volume stores running complex order reports can hit slow queries on
wp_postswhen filtering bypost_status,post_type, andpost_datesimultaneously. - User meta queries: Membership plugins and LMS platforms that store user progress or access levels in
wp_usermetacan create slow queries if those meta keys are not indexed.
Use EXPLAIN in MySQL to inspect query execution plans. Any query showing type: ALL (full table scan) on a large table is a candidate for index optimization. Consult your database administrator or a senior WordPress developer before adding custom indexes — a poorly chosen index adds write overhead without solving the read problem.
Step 7: Address WooCommerce-Specific Table Growth
WooCommerce introduces several tables that grow aggressively: wp_woocommerce_sessions, wp_woocommerce_log, action scheduler tables, and the order tables introduced in WooCommerce 7.1 via High Performance Order Storage (HPOS). Each has its own cleanup requirements.
Session table cleanup
Guest sessions in wp_woocommerce_sessions expire after a configurable period, but expired sessions are only purged when the WooCommerce cleanup cron job runs. On high-traffic stores, this table can hold millions of rows. Verify that WordPress cron is running reliably — if cron jobs are silently failing, session cleanup stops entirely.
Action Scheduler table growth
The Action Scheduler (used extensively by WooCommerce) logs every scheduled action in wp_actionscheduler_actions and wp_actionscheduler_logs. By default, completed and failed actions are retained for 30 days. On a busy store, this produces tens of thousands of rows per day. Review the retention settings and consider reducing the retention period for completed actions to 7–14 days if historical action logs are not operationally necessary.
Step 8: Implement a Recurring Database Maintenance Schedule
A one-time cleanup does not solve a structural problem. Database bloat is continuous — it is a byproduct of normal WordPress operation. The checklist only pays off when it becomes a scheduled routine, not a reactive fire drill.
Suggested maintenance cadence
- Weekly: Delete expired transients, purge WooCommerce sessions, check slow query log for new patterns
- Monthly: Run OPTIMIZE TABLE on high-write tables, review autoloaded data size, audit new plugin additions for autoload behavior
- Quarterly: Full database audit — review table sizes, index usage statistics, orphaned meta cleanup, backup verification
Agencies managing multiple client sites should systematize this into their maintenance retainer scope. Sites that receive this treatment consistently outperform those that only get attention when something breaks — and the diagnostic data from routine audits often surfaces problems before they become client-facing incidents.
If your team needs a reliable technical partner to manage this kind of systematic database care across client projects, get in touch with us here — we work with agencies as a white-label development partner.
Frequently Asked Questions
How often should I run a WordPress database optimization?
For active sites with regular content updates, monthly table optimization is a reasonable baseline. WooCommerce stores with high order volume — say, 100+ orders per day — benefit from weekly optimization of the order and session tables. Static or low-activity sites can run quarterly.
Will deleting revisions affect my published content?
No. Post revisions are drafts stored for rollback purposes. Deleting them removes the version history but does not affect published content. Cap revisions going forward with WP_POST_REVISIONS to prevent the problem from recurring.
What is a safe autoloaded data size for WordPress?
Under 1MB is the generally accepted target for a healthy WordPress install. Sites between 1–3MB may notice minor slowdowns on uncached pages. Sites above 5MB should treat autoloaded data cleanup as a high-priority item — the performance impact on admin pages and dynamic content is measurable.
Does a persistent object cache eliminate the need for database optimization?
It reduces the frequency and urgency of some cleanup tasks, but it does not eliminate them. A persistent object cache like Redis bypasses database reads for cached data — but uncached queries (cold cache, logged-in users, WooCommerce cart pages) still hit the database. Underlying table health and index coverage still matter.
Can I run these optimizations on a live site without downtime?
Most cleanup operations — deleting transients, removing revisions, purging sessions — are low-risk and can run during off-peak hours without visible downtime. OPTIMIZE TABLE on large tables (1M+ rows) carries more risk and should be scheduled during a maintenance window or executed with online schema change tools. Always take a verified database backup before any bulk operation.
Developer experience
What I keep seeing in practice is that database performance is treated as a one-time fix rather than an ongoing discipline. I’ve audited WordPress installs where autoloaded data alone was sitting at 12MB — on every single page request — and the agency had no idea because the site «felt fine» on cached pages. It only surfaced when a client added a WooCommerce membership layer and suddenly admin load times doubled. The checklist matters, but the cadence matters more. Getting the database into good shape once is easy. Keeping it there across twelve months of plugin updates, content growth, and WooCommerce order volume is where most teams drop the ball.
