Resolving MySQL OOM Caused by Triggers and table_open_cache_instances
This article analyzes a MySQL replica that repeatedly ran out of memory due to large triggers and a high table_open_cache_instances setting, demonstrates how to reproduce the issue with test scripts, and provides a practical fix by reducing the parameter to mitigate OOM.
1 Problem Description
A replica server's memory usage kept increasing until the MySQL service was killed.
The memory monitoring view showed a usage of 92.76% and a kill event around 00:00, after which mysqld_safe restarted the process and memory rose again.
2 Investigation Process
Basic Information
Database version: MySQL 5.7.32
Operating system: Ubuntu 20.04
Host configuration: 8C 64GB innodb_buffer_pool_size: 8G
The my.cnf did not enable memory‑related monitoring, so the following setting was added:
performance-schema-instrument = 'memory/% = COUNTED'After enabling memory monitoring and waiting, the relevant Performance Schema views displayed that the InnoDB buffer pool size was allocated correctly, but the memory/sql/sp_head::main_mem_root component consumed about 8 GB.
According to the source code, sp_head represents an instance of a stored program (procedure, function, trigger, or event).
Queries showed a large number of triggers and stored procedures in the environment.
A MySQL bug (ID 86821) mentions that a high table_open_cache_instances value can cause excessive memory usage when many large triggers are present, and recommends setting the variable to 1 in such cases.
The parameter table_open_cache_instances defaults to 8 or 16 on systems with many cores; each instance creates its own table cache, and when a table is cached, all associated triggers are stored in memory/sql/sp_head::main_mem_root . The larger the setting, the more memory is consumed by triggers and stored procedures, eventually leading to OOM.
Verification with table_open_cache_instances = 8
# Clear cache
mysql> flush tables;
for i in `seq 1 1 8`
do
mysql -uroot -p test -e "select * from test;"
done
mysql> show variables like '%table_open_cache_instances%';
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| table_open_cache_instances | 8 |
+----------------------------+-------+
mysql> SELECT current_alloc FROM sys.memory_global_by_current_bytes WHERE event_name='memory/sql/sp_head::main_mem_root';
+--------------+
| current_alloc |
+--------------+
| 119.61 KiB |
+--------------+A trigger was then created on the test table, and the table was accessed repeatedly. The memory usage for memory/sql/sp_head::main_mem_root grew to about 439 KiB, confirming that many large triggers significantly increase memory consumption.
Verification with table_open_cache_instances = 1
# Clear cache
mysql> flush tables;
mysql> show variables like '%table_open_cache_instances%';
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| table_open_cache_instances | 1 |
+----------------------------+-------+
mysql> SELECT current_alloc FROM sys.memory_global_by_current_bytes WHERE event_name='memory/sql/sp_head::main_mem_root';
+--------------+
| current_alloc |
+--------------+
| 119.61 KiB |
+--------------+
# Access table
mysql> system sh test.sh;
mysql> SELECT current_alloc FROM sys.memory_global_by_current_bytes WHERE event_name='memory/sql/sp_head::main_mem_root';
+--------------+
| current_alloc |
+--------------+
| 159.53 KiB |
+--------------+With the parameter set to 1, the memory growth was much smaller.
Applying the same change to the problematic replica (setting table_open_cache_instances to 1) stabilized the memory usage and prevented further OOM incidents.
3 Summary
MySQL does not recommend using a large number of triggers or complex stored procedures.
Setting table_open_cache_instances to 1 can reduce memory consumption, though it may affect SQL performance under high concurrency; adjust according to workload.
The more triggers present, the larger the memory occupied by memory/sql/sp_head::main_mem_root , and the more memory stored procedures will use.
This article provides one direction to solve OOM; deeper kernel‑level details should be explored independently.
References
[1] sp_head: https://dev.mysql.com/doc/dev/mysql-server/latest/classsp__head.html#details
[2] Bug 86821: https://bugs.mysql.com/bug.php?id=86821
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Aikesheng Open Source Community
The Aikesheng Open Source Community provides stable, enterprise‑grade MySQL open‑source tools and services, releases a premium open‑source component each year (1024), and continuously operates and maintains them.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
