MySQL allocates buffers and caches to improve performance of database operations. The default configuration is designed to permit a MySQL server to start on a virtual machine that has approximately 512MB of RAM. You can improve MySQL performance by increasing the values of certain cache and buffer-related system variables. You can also modify the default configuration to run MySQL on systems with limited memory.
The following list describes some of the ways that MySQL uses memory. Where applicable, relevant system variables are referenced. Some items are storage engine or feature specific.
-
The
InnoDB
buffer pool is a memory area that holds cachedInnoDB
data for tables, indexes, and other auxiliary buffers. For efficiency of high-volume read operations, the buffer pool is divided into pages that can potentially hold multiple rows. For efficiency of cache management, the buffer pool is implemented as a linked list of pages; data that is rarely used is aged out of the cache, using a variation of the LRU algorithm. For more information, see Section 14.5.1, “Buffer Pool”.The size of the buffer pool is important for system performance:
-
InnoDB
allocates memory for the entire buffer pool at server startup, usingmalloc()
operations. Theinnodb_buffer_pool_size
system variable defines the buffer pool size. Typically, a recommendedinnodb_buffer_pool_size
value is 50 to 75 percent of system memory.innodb_buffer_pool_size
can be configured dynamically, while the server is running. For more information, see Section 14.8.3.1, “Configuring InnoDB Buffer Pool Size”. -
On systems with a large amount of memory, you can improve concurrency by dividing the buffer pool into multiple buffer pool instances. The
innodb_buffer_pool_instances
system variable defines the number of buffer pool instances. -
A buffer pool that is too small may cause excessive churning as pages are flushed from the buffer pool only to be required again a short time later.
-
A buffer pool that is too large may cause swapping due to competition for memory.
-
-
All threads share the
MyISAM
key buffer. Thekey_buffer_size
system variable determines its size.For each
MyISAM
table the server opens, the index file is opened once; the data file is opened once for each concurrently running thread that accesses the table. For each concurrent thread, a table structure, column structures for each column, and a buffer of size3 *
are allocated (whereN
N
is the maximum row length, not countingBLOB
columns). ABLOB
column requires five to eight bytes plus the length of theBLOB
data. TheMyISAM
storage engine maintains one extra row buffer for internal use. -
The
myisam_use_mmap
system variable can be set to 1 to enable memory-mapping for allMyISAM
tables. -
If an internal in-memory temporary table becomes too large (as determined using the
tmp_table_size
andmax_heap_table_size
system variables), MySQL automatically converts the table from in-memory to on-disk format. On-disk temporary tables use the storage engine defined by theinternal_tmp_disk_storage_engine
system variable. You can increase the permissible temporary table size as described in Section 8.4.4, “Internal Temporary Table Use in MySQL”.For
MEMORY
tables explicitly created withCREATE TABLE
, only themax_heap_table_size
system variable determines how large a table can grow, and there is no conversion to on-disk format. -
The MySQL Performance Schema is a feature for monitoring MySQL server execution at a low level. The Performance Schema dynamically allocates memory incrementally, scaling its memory use to actual server load, instead of allocating required memory during server startup. Once memory is allocated, it is not freed until the server is restarted. For more information, see Section 25.17, “The Performance Schema Memory-Allocation Model”.
-
Each thread that the server uses to manage client connections requires some thread-specific space. The following list indicates these and which system variables control their size:
-
A stack (
thread_stack
) -
A connection buffer (
net_buffer_length
) -
A result buffer (
net_buffer_length
)
The connection buffer and result buffer each begin with a size equal to
net_buffer_length
bytes, but are dynamically enlarged up tomax_allowed_packet
bytes as needed. The result buffer shrinks tonet_buffer_length
bytes after each SQL statement. While a statement is running, a copy of the current statement string is also allocated.Each connection thread uses memory for computing statement digests. The server allocates
max_digest_length
bytes per session. See Section 25.10, “Performance Schema Statement Digests”. -
-
All threads share the same base memory.
-
When a thread is no longer needed, the memory allocated to it is released and returned to the system unless the thread goes back into the thread cache. In that case, the memory remains allocated.
-
Each request that performs a sequential scan of a table allocates a read buffer. The
read_buffer_size
system variable determines the buffer size. -
When reading rows in an arbitrary sequence (for example, following a sort), a random-read buffer may be allocated to avoid disk seeks. The
read_rnd_buffer_size
system variable determines the buffer size. -
All joins are executed in a single pass, and most joins can be done without even using a temporary table. Most temporary tables are memory-based hash tables. Temporary tables with a large row length (calculated as the sum of all column lengths) or that contain
BLOB
columns are stored on disk. -
Most requests that perform a sort allocate a sort buffer and zero to two temporary files depending on the result set size. See Section B.4.3.5, “Where MySQL Stores Temporary Files”.
-
Almost all parsing and calculating is done in thread-local and reusable memory pools. No memory overhead is needed for small items, thus avoiding the normal slow memory allocation and freeing. Memory is allocated only for unexpectedly large strings.
-
For each table having
BLOB
columns, a buffer is enlarged dynamically to read in largerBLOB
values. If you scan a table, the buffer grows as large as the largestBLOB
value. -
MySQL requires memory and descriptors for the table cache. Handler structures for all in-use tables are saved in the table cache and managed as “First In, First Out” (FIFO). The
table_open_cache
system variable defines the initial table cache size; see Section 8.4.3.1, “How MySQL Opens and Closes Tables”.MySQL also requires memory for the table definition cache. The
table_definition_cache
system variable defines the number of table definitions (from.frm
files) that can be stored in the table definition cache. If you use a large number of tables, you can create a large table definition cache to speed up the opening of tables. The table definition cache takes less space and does not use file descriptors, unlike the table cache. -
A
FLUSH TABLES
statement or mysqladmin flush-tables command closes all tables that are not in use at once and marks all in-use tables to be closed when the currently executing thread finishes. This effectively frees most in-use memory.FLUSH TABLES
does not return until all tables have been closed. -
The server caches information in memory as a result of
GRANT
,CREATE USER
,CREATE SERVER
, andINSTALL PLUGIN
statements. This memory is not released by the correspondingREVOKE
,DROP USER
,DROP SERVER
, andUNINSTALL PLUGIN
statements, so for a server that executes many instances of the statements that cause caching, there will be an increase in cached memory use unless it is freed withFLUSH PRIVILEGES
.
ps and other system status programs may report that mysqld uses a lot of memory. This may be caused by thread stacks on different memory addresses. For example, the Solaris version of ps counts the unused memory between stacks as used memory. To verify this, check available swap with swap -s
. We test mysqld with several memory-leakage detectors (both commercial and Open Source), so there should be no memory leaks.
The following example demonstrates how to use Performance Schema and sys schema to monitor MySQL memory usage.
Most Performance Schema memory instrumentation is disabled by default. Instruments can be enabled by updating the ENABLED
column of the Performance Schema setup_instruments
table. Memory instruments have names in the form of memory/
, where code_area
/instrument_name
code_area
is a value such as sql
or innodb
, and instrument_name
is the instrument detail.
-
To view available MySQL memory instruments, query the Performance Schema
setup_instruments
table. The following query returns hundreds of memory instruments for all code areas.mysql>
SELECT * FROM performance_schema.setup_instruments
WHERE NAME LIKE '%memory%';
You can narrow results by specifying a code area. For example, you can limit results to
InnoDB
memory instruments by specifyinginnodb
as the code area.mysql>
SELECT * FROM performance_schema.setup_instruments
WHERE NAME LIKE '%memory/innodb%';
+-------------------------------------------+---------+-------+ | NAME | ENABLED | TIMED | +-------------------------------------------+---------+-------+ | memory/innodb/adaptive hash index | NO | NO | | memory/innodb/buf_buf_pool | NO | NO | | memory/innodb/dict_stats_bg_recalc_pool_t | NO | NO | | memory/innodb/dict_stats_index_map_t | NO | NO | | memory/innodb/dict_stats_n_diff_on_level | NO | NO | | memory/innodb/other | NO | NO | | memory/innodb/row_log_buf | NO | NO | | memory/innodb/row_merge_sort | NO | NO | | memory/innodb/std | NO | NO | | memory/innodb/trx_sys_t::rw_trx_ids | NO | NO | ...Depending on your MySQL installation, code areas may include
performance_schema
,sql
,client
,innodb
,myisam
,csv
,memory
,blackhole
,archive
,partition
, and others. -
To enable memory instruments, add a
performance-schema-instrument
rule to your MySQL configuration file. For example, to enable all memory instruments, add this rule to your configuration file and restart the server:performance-schema-instrument='memory/%=COUNTED'
NoteEnabling memory instruments at startup ensures that memory allocations that occur at startup are counted.
After restarting the server, the
ENABLED
column of the Performance Schemasetup_instruments
table should reportYES
for memory instruments that you enabled. TheTIMED
column in thesetup_instruments
table is ignored for memory instruments because memory operations are not timed.mysql>
SELECT * FROM performance_schema.setup_instruments
WHERE NAME LIKE '%memory/innodb%';
+-------------------------------------------+---------+-------+ | NAME | ENABLED | TIMED | +-------------------------------------------+---------+-------+ | memory/innodb/adaptive hash index | NO | NO | | memory/innodb/buf_buf_pool | NO | NO | | memory/innodb/dict_stats_bg_recalc_pool_t | NO | NO | | memory/innodb/dict_stats_index_map_t | NO | NO | | memory/innodb/dict_stats_n_diff_on_level | NO | NO | | memory/innodb/other | NO | NO | | memory/innodb/row_log_buf | NO | NO | | memory/innodb/row_merge_sort | NO | NO | | memory/innodb/std | NO | NO | | memory/innodb/trx_sys_t::rw_trx_ids | NO | NO | ... -
Query memory instrument data. In this example, memory instrument data is queried in the Performance Schema
memory_summary_global_by_event_name
table, which summarizes data byEVENT_NAME
. TheEVENT_NAME
is the name of the instrument.The following query returns memory data for the
InnoDB
buffer pool. For column descriptions, see Section 25.12.15.9, “Memory Summary Tables”.mysql>
SELECT * FROM performance_schema.memory_summary_global_by_event_name
WHERE EVENT_NAME LIKE 'memory/innodb/buf_buf_pool'\G
EVENT_NAME: memory/innodb/buf_buf_pool COUNT_ALLOC: 1 COUNT_FREE: 0 SUM_NUMBER_OF_BYTES_ALLOC: 137428992 SUM_NUMBER_OF_BYTES_FREE: 0 LOW_COUNT_USED: 0 CURRENT_COUNT_USED: 1 HIGH_COUNT_USED: 1 LOW_NUMBER_OF_BYTES_USED: 0 CURRENT_NUMBER_OF_BYTES_USED: 137428992 HIGH_NUMBER_OF_BYTES_USED: 137428992The same underlying data can be queried using the
sys
schemamemory_global_by_current_bytes
table, which shows current memory usage within the server globally, broken down by allocation type.mysql>
SELECT * FROM sys.memory_global_by_current_bytes
WHERE event_name LIKE 'memory/innodb/buf_buf_pool'\G
*************************** 1. row *************************** event_name: memory/innodb/buf_buf_pool current_count: 1 current_alloc: 131.06 MiB current_avg_alloc: 131.06 MiB high_count: 1 high_alloc: 131.06 MiB high_avg_alloc: 131.06 MiBThis
sys
schema query aggregates currently allocated memory (current_alloc
) by code area:mysql>
SELECT SUBSTRING_INDEX(event_name,'/',2) AS
code_area, sys.format_bytes(SUM(current_alloc))
AS current_alloc
FROM sys.x$memory_global_by_current_bytes
GROUP BY SUBSTRING_INDEX(event_name,'/',2)
ORDER BY SUM(current_alloc) DESC;
+---------------------------+---------------+ | code_area | current_alloc | +---------------------------+---------------+ | memory/innodb | 843.24 MiB | | memory/performance_schema | 81.29 MiB | | memory/mysys | 8.20 MiB | | memory/sql | 2.47 MiB | | memory/memory | 174.01 KiB | | memory/myisam | 46.53 KiB | | memory/blackhole | 512 bytes | | memory/federated | 512 bytes | | memory/csv | 512 bytes | | memory/vio | 496 bytes | +---------------------------+---------------+For more information about
sys
schema, see Chapter 26, MySQL sys Schema.
Some hardware/operating system architectures support memory pages greater than the default (usually 4KB). The actual implementation of this support depends on the underlying hardware and operating system. Applications that perform a lot of memory accesses may obtain performance improvements by using large pages due to reduced Translation Lookaside Buffer (TLB) misses.
In MySQL, large pages can be used by InnoDB, to allocate memory for its buffer pool and additional memory pool.
Standard use of large pages in MySQL attempts to use the largest size supported, up to 4MB. Under Solaris, a “super large pages” feature enables uses of pages up to 256MB. This feature is available for recent SPARC platforms. It can be enabled or disabled by using the --super-large-pages
or --skip-super-large-pages
option.
MySQL also supports the Linux implementation of large page support (which is called HugeTLB in Linux).
Before large pages can be used on Linux, the kernel must be enabled to support them and it is necessary to configure the HugeTLB memory pool. For reference, the HugeTBL API is documented in the Documentation/vm/hugetlbpage.txt
file of your Linux sources.
The kernel for some recent systems such as Red Hat Enterprise Linux appear to have the large pages feature enabled by default. To check whether this is true for your kernel, use the following command and look for output lines containing “huge”:
shell> cat /proc/meminfo | grep -i huge
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 4096 kB
The nonempty command output indicates that large page support is present, but the zero values indicate that no pages are configured for use.
If your kernel needs to be reconfigured to support large pages, consult the hugetlbpage.txt
file for instructions.
Assuming that your Linux kernel has large page support enabled, configure it for use by MySQL using the following commands. Normally, you put these in an rc
file or equivalent startup file that is executed during the system boot sequence, so that the commands execute each time the system starts. The commands should execute early in the boot sequence, before the MySQL server starts. Be sure to change the allocation numbers and the group number as appropriate for your system.
# Set the number of pages to be used.
# Each page is normally 2MB, so a value of 20 = 40MB.
# This command actually allocates memory, so this much
# memory must be available.
echo 20 > /proc/sys/vm/nr_hugepages
# Set the group number that is permitted to access this
# memory (102 in this case). The mysql user must be a
# member of this group.
echo 102 > /proc/sys/vm/hugetlb_shm_group
# Increase the amount of shmem permitted per segment
# (12G in this case).
echo 1560281088 > /proc/sys/kernel/shmmax
# Increase total amount of shared memory. The value
# is the number of pages. At 4KB/page, 4194304 = 16GB.
echo 4194304 > /proc/sys/kernel/shmall
For MySQL usage, you normally want the value of shmmax
to be close to the value of shmall
.
To verify the large page configuration, check /proc/meminfo
again as described previously. Now you should see some nonzero values:
shell> cat /proc/meminfo | grep -i huge
HugePages_Total: 20
HugePages_Free: 20
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 4096 kB
The final step to make use of the hugetlb_shm_group
is to give the mysql
user an “unlimited” value for the memlock limit. This can be done either by editing /etc/security/limits.conf
or by adding the following command to your mysqld_safe script:
ulimit -l unlimited
Adding the ulimit command to mysqld_safe causes the root
user to set the memlock limit to unlimited
before switching to the mysql
user. (This assumes that mysqld_safe is started by root
.)
Large page support in MySQL is disabled by default. To enable it, start the server with the --large-pages
option. For example, you can use the following lines in the server my.cnf
file:
[mysqld] large-pages
With this option, InnoDB
uses large pages automatically for its buffer pool and additional memory pool. If InnoDB
cannot do this, it falls back to use of traditional memory and writes a warning to the error log: Warning: Using conventional memory pool
To verify that large pages are being used, check /proc/meminfo
again:
shell> cat /proc/meminfo | grep -i huge
HugePages_Total: 20
HugePages_Free: 20
HugePages_Rsvd: 2
HugePages_Surp: 0
Hugepagesize: 4096 kB