Skip to content

Performance

When the database is the bottleneck, not PHP

Learn how to tell a slow query from a PHP limit and what to fix first on your hosting account.

Updated Aug 29, 20264 min read11 reads
When the database is the bottleneck, not PHP
CPU idle while workers wait on MySQL means the database is the bottleneck

When the database is the bottleneck, not PHP, your site stays slow even though PHP barely uses the CPU. Workers sit in D-state or inside a mysql call, time to first byte climbs, and the real work is stuck on a query, a missing index, or a remote database path. Extra PHP children only make more processes wait on the same statement, so the pile-up gets worse instead of better.

MariaDB should spend CPU on the queries your pages actually need. A quiet database is not automatically healthy. A busy, well-indexed InnoDB engine doing useful work is fine. A single unindexed scan that fires thousands of times per page is not, and that pattern often looks like a PHP problem until you read the process list.

How to recognize the bottleneck

You will often see low user CPU on PHP while TTFB stays high. The homepage feels heavy, yet top or your process view shows workers waiting on the database rather than executing code. That pattern points to a bad query, missing indexes, oversized autoloaded options, or a database host that is farther away than you think.

On WordPress, autoloaded rows in wp_options are a common cause because large blobs load on every request. Unindexed postmeta lookups create the same kind of wait. A remote database in another data center adds a floor to every round trip, so the worker looks busy while it is only blocked on the network.

What to do in the first hour

Do not raise max_children first. Capture SHOW FULL PROCESSLIST from the MySQL client, phpMyAdmin, or WP Toolkit on WordPress accounts. The row stuck in Sending data or Waiting for table metadata lock is usually the lead. Copy that query and run EXPLAIN on it. If type is ALL on a large table, you have found the expensive path.

Query Monitor on a staging copy can name the pile when process list output is hard to read. Keep that toolbar off production. On a VPS you can also enable the slow query log for a short window, then turn it off. Leave a zero-second cutoff running forever only if you are ready to manage a very large log.

Fix the query before you add capacity

Add the missing index or rewrite the statement so it stops scanning whole tables. After the query is sane, page cache still helps anonymous traffic and reduces repeat work. If the InnoDB buffer pool is small and the working set is not, more RAM can help next. Check that only after you trust the SQL.

If the database lives on another host, measure latency before you buy memory on the web server. Time a trivial SELECT 1 and a simple ping. At roughly 20 ms per round trip, a page that runs fifty queries already spends about a second waiting, with or without cached objects in front.

If you already raised PHP workers and load climbed, lower them again. They were a crowd at the same locked door. Shared hosting gives you cPanel tools without root, while a KVM VPS gives you root when you need the slow query log and full process control. In both cases the order stays the same: identify the statement, fix the index, then cache, then consider RAM.

Share

Send this article

Need someone else to do this? Send them the link — the commands are in the article.

Tagged

Was this article helpful?

Be the first to rate this article.