Using the MySQL Performance Schema for Deep Query Analysis
AI generated
InnoDB
SQL
MySQL · Performance Schema · Diagnostics
Performance Schema
Statement, wait and stage instrumentation for deep query analysis

The Performance Schema measures what actually happens inside a running MySQL instance: which statements run how often and for how long, which waits they get stuck on, and which stage consumes their time. Anyone who wants to find expensive query patterns in a Magento store systematically instead of by guesswork cannot avoid this instrumentation.

11 min read events_statements_summary_by_digest Statement Digests

1. How the Performance Schema instruments MySQL

The performance_schema database is populated at runtime by measurement points built directly into the server code, not by an external profiler attached from outside. Each of these measurement points is called an instrument and covers a clearly scoped activity: a statement, a wait on a mutex, a file access, or a memory allocation. Instruments are named hierarchically, for example statement/sql/select or wait/synch/mutex/innodb/buf_pool_mutex, so whole groups can be enabled or disabled through wildcards.

Separate from instruments, consumers control whether the measured raw data actually gets written into a table at all. An enabled instrument without an enabled consumer still generates an event, but that event is never stored and costs almost nothing. This split lets measurement and storage be dialed independently, instead of either recording everything or nothing at all.

2. Configuring instruments, consumers and actors deliberately

The setup_instruments and setup_consumers tables control both levels through simple updates. In MySQL 8.0, statement instruments and their digest summary are active by default, while many wait and stage instruments stay deliberately disabled to keep the baseline load low. Anyone who needs a deeper diagnosis enables the relevant groups for the duration of the investigation and switches them off again afterward.

On top of that, setup_actors defines which users and hosts get instrumented at all. In a Magento setup with several database users, for example a separate application user and a reporting user, filtering deliberately reduces the volume of generated events noticeably without losing sight of the connections that actually matter.


-- Statement digest stays enabled (default), only enable wait
-- instruments for the duration of a diagnostic session
UPDATE performance_schema.setup_instruments
SET ENABLED = 'YES', TIMED = 'YES'
WHERE NAME LIKE 'wait/synch/mutex/innodb/%';

UPDATE performance_schema.setup_consumers
SET ENABLED = 'YES'
WHERE NAME LIKE 'events_waits_%';

-- Only instrument the storefront application user
UPDATE performance_schema.setup_actors
SET ENABLED = 'YES', HISTORY = 'YES'
WHERE HOST = '%' AND USER = 'magento_app';

3. The digest model behind events_statements_summary_by_digest

The digest mechanism normalizes every executed statement by replacing literals with placeholders and unifying whitespace. Two queries that differ only in the concrete product ID or store code end up under the same DIGEST hash and the same DIGEST_TEXT. That is exactly what an ORM-heavy application like Magento needs, since it executes the same logical query in countless parameter variants without each one showing up as a separate entry.

The events_statements_summary_by_digest table aggregates, per digest, columns such as COUNT_STAR, SUM_TIMER_WAIT, AVG_TIMER_WAIT, SUM_ROWS_EXAMINED, SUM_ROWS_SENT, SUM_NO_INDEX_USED and SUM_SELECT_FULL_JOIN. From these columns you can tell whether a query pattern is expensive because it runs often, because a single execution takes a long time, or because it scans far more rows than it ever needs to return.

4. Identifying expensive query patterns with a targeted query

Day to day diagnosis needs just one query sorted by aggregated execution time. The TIMER columns are stored in picoseconds and need converting for readable values. It matters to keep an eye on COUNT_STAR as well, not just the raw sum: a pattern with moderate per-execution cost that runs hundreds of thousands of times an hour often adds up to more total server load than a single, rare reporting query.

A second, often more revealing angle is the ratio of SUM_ROWS_EXAMINED to SUM_ROWS_SENT. A wide gap between the two, combined with SUM_NO_INDEX_USED greater than zero, almost always points to a missing or poorly designed index, which can then be confirmed with EXPLAIN against exactly that digest text.


SELECT
  DIGEST_TEXT,
  COUNT_STAR AS exec_count,
  ROUND(SUM_TIMER_WAIT / 1000000000000, 2) AS total_seconds,
  ROUND(AVG_TIMER_WAIT / 1000000000, 2) AS avg_ms,
  SUM_ROWS_EXAMINED,
  SUM_ROWS_SENT,
  SUM_NO_INDEX_USED
FROM performance_schema.events_statements_summary_by_digest
ORDER BY SUM_TIMER_WAIT DESC
LIMIT 20;

5. Wait events: exposing contention at the mutex and I/O level

While statement digests show which query is expensive, wait events show why it is waiting. Instruments such as wait/synch/mutex/innodb/buf_pool_mutex or wait/io/file/innodb/innodb_data_file measure internal wait time on locks, mutexes and file access, aggregated in events_waits_summary_global_by_event_name. Only this level explains whether a slow query is genuinely a missed optimization or contention on a shared internal structure that many threads are stuck behind at the same time.

Wait instruments are far more numerous and fine grained than statement instruments, which is why they stay disabled by default. Enabling them for a bounded diagnostic window and disabling them again afterward delivers the necessary depth without turning the instrumentation itself into a permanent cost on a heavily loaded production system.

6. Stage events: tracing a statement's lifecycle

Stage events take over the role of the now removed SHOW PROFILE and show which phase a statement spends its time in, for example starting, checking permissions, Sending data or closing tables. The events_stages_history_long table keeps these phases per thread and makes visible whether the measured runtime actually sits in server execution or mostly in shipping a large result set to the client.

For Magento this matters most for export and reporting queries that return large data volumes. If the stage analysis shows most of the time spent in Sending data, a faster network link or a leaner result set helps more than yet another index optimization that misses the real cause.

7. Weighing the overhead full instrumentation costs in production

Plain statement digest instrumentation is enabled by default in MySQL 8.0 and, thanks to a largely lock-free design, adds single-digit percent CPU overhead, which is acceptable for practically any Magento store. Things look different once events_statements_history_long plus fine grained wait and stage instruments are all enabled at once: at very high query rates the per-event overhead adds up noticeably and can become measurable on systems that are already CPU bound.

The pragmatic recommendation is to leave digest aggregation running permanently but enable wait and stage instrumentation only for bounded diagnostic windows. Anyone who needs deep instrumentation regularly should measure the actual extra load on a staging system under realistic traffic instead of relying on generic percentage figures from the documentation, since the real effect depends heavily on hardware and query mix.

8. Sizing, persistence and handling a digest reset correctly

The digest table is capped in size via performance_schema_digest_size. Once it is full, new, previously unseen digests get bundled into a generic overflow entry, losing exactly the granularity a clean analysis relies on. On a store with many distinct query shapes, for example from dynamic layered navigation filters, a deliberately higher value pays off compared to the server's automatic default sizing.

All Performance Schema data lives purely in memory and does not survive a restart. For a clean before-and-after comparison, for example around a deployment or a load test, an explicit TRUNCATE TABLE on the relevant summary tables right before the run keeps old measurements from diluting the new evaluation.


-- Reset digest statistics right before a targeted load test
TRUNCATE TABLE performance_schema.events_statements_summary_by_digest;

-- Raise the digest table size permanently via the config file
-- (only takes effect after a restart):
-- performance_schema_digest_size = 20000

9. Practical example: finding the most expensive category and product queries

In practice, the digest report is additionally filtered on table names that are typical Magento hotspots, such as catalog_product_entity, catalog_category_product or sales_order_grid. During a load spike window, for example a promotion day, this lets you pick out exactly the query patterns responsible for the largest share of aggregated database time instead of working through thousands of irrelevant individual entries.

Combining this filtering with the ratio of examined to returned rows produces a clear priority order: patterns with a high SUM_NO_INDEX_USED value and a poor row ratio are almost always genuine index gaps and can be fixed quickly, while patterns with a good ratio but high execution frequency are better candidates for caching or reducing how often the application code calls them in the first place.


SELECT DIGEST_TEXT, COUNT_STAR, SUM_NO_INDEX_USED,
       ROUND(AVG_TIMER_WAIT / 1000000000, 2) AS avg_ms
FROM performance_schema.events_statements_summary_by_digest
WHERE DIGEST_TEXT LIKE '%catalog_product_entity%'
   OR DIGEST_TEXT LIKE '%catalog_category_product%'
ORDER BY AVG_TIMER_WAIT DESC
LIMIT 15;
Level Example instrument Consumer table Typical use
Statement statement/sql/select events_statements_summary_by_digest Aggregating expensive query patterns over time
Wait wait/synch/mutex/innodb/... events_waits_summary_global_by_event_name Finding internal lock and mutex contention
Stage stage/sql/Sending data events_stages_history_long Tracing where execution time actually goes
Memory memory/innodb/buf_buf_pool memory_summary_global_by_event_name Checking memory use of individual subsystems

Mironsoft

Database performance, index tuning, and Magento DB optimization

A Magento shop suffering from slow database queries?

We analyze MySQL databases for performance bottlenecks, optimize indexes and queries with purpose, and set up backup and replication strategies that actually work when it counts.

Performance Audit

Systematically investigate the slow query log and explain plans for bottlenecks.

Index Optimization

Build indexes with purpose for the shop's actual query load.

Backup Strategy

Set up reliable backup and restore processes for production Magento databases.

10. Summary

Performance Schema for Query Analysis: The Essentials at a Glance

Two-tier model

Instruments measure raw events, consumers decide whether and where that data gets stored, both configurable independently.

Digest aggregation

events_statements_summary_by_digest normalizes literals and groups equivalent queries into one analyzable pattern.

Overhead

Statement digests are cheap to run permanently, wait and stage instrumentation belong in a bounded diagnostic window.

Sizing

Size the digest table deliberately and create a clean baseline with TRUNCATE before targeted tests.

11. FAQ: Performance Schema for Query Analysis: The Essentials at a Glance

1What is the difference between an instrument and a consumer?
An instrument measures a specific activity such as a statement or a mutex wait. A consumer decides whether that measurement actually gets written to a table. Both can be enabled independently.
2Why are literals in DIGEST_TEXT replaced with placeholders?
So structurally identical queries with different parameters, such as different product IDs, get aggregated under the same digest instead of appearing as separate entries.
3What unit are the TIMER columns stored in?
Picoseconds. For readable second or millisecond values, divide by 1000000000000 or 1000000000 respectively.
4Is the Performance Schema enabled by default?
Statement digests are enabled by default in MySQL 8.0. Many wait and stage instruments, however, are disabled by default and must be turned on deliberately.
5How much overhead does full instrumentation add?
Statement digests cost single-digit percent overhead. Full wait and stage instrumentation at very high query rates can cost noticeably more and should only run for a bounded time.
6What happens once the digest table is full?
New, previously unseen digests get bundled into a generic overflow entry, losing granularity for new query patterns. performance_schema_digest_size should be sized accordingly.
7Does Performance Schema data survive a restart?
No, all data lives purely in memory and is lost on restart. For before-and-after comparisons, use a targeted TRUNCATE right before the test run instead.
8How do I find queries with a missing index?
Via the SUM_NO_INDEX_USED column in events_statements_summary_by_digest, combined with an unfavorable ratio of SUM_ROWS_EXAMINED to SUM_ROWS_SENT.
9Does the Performance Schema replace EXPLAIN?
No, it complements EXPLAIN. The Performance Schema shows which query patterns are most expensive over time, EXPLAIN then explains why a specific execution plan looks the way it does.
10Can I limit instrumentation to a single database user?
Yes, the setup_actors table defines which users and hosts generate events at all, which reduces overhead in multi-user environments.