How to Improve MySQL Server Performance with Proper Optimization

Advertisement

MySQL server optimization is an important step in improving the performance and efficiency of the database system. The need for fast and accurate data is increasing in the ever-evolving digital era.

Advertisement

MySQL, as one of the popular database systems, requires the right optimization to meet this need. Thus, MySQL server optimization not only helps to improve performance but also ensures the security and scalability of the system.

The main purpose of this article is to provide a complete guide on how to improve MySQL server performance. This article will discuss practical steps to optimize MySQL configuration, manage memory usage, and use cache effectively. Thus, users can understand how to improve the performance of MySQL servers to meet the needs of complex and dynamic applications.

Advertisement
MySQL Server Performance

MySQL Server Optimization Steps

  1. Using a Sensitive Initial Configuration
  2. Managing Memory Usage
  3. Setting Memory Usage for Connections
  4. Setting Memory Usage for Queries
  5. Setting Up Memory for the Operating System
  6. Setting Memory for Cache
  7. Setting Up Cache for MyISAM
  8. Setting Up Cache for InnoDB
  9. Testing and Monitoring

1. Using a Sensitive Initial Configuration

Using the MySQL Configuration Sample

MySQL provides several sample configuration files that can be used as a starting point for optimizing the server. These files are usually found in the MySQL installation directory and have names such as my-small.cnf, my-medium.cnf, my-large.cnf, and my-huge.cnf. These files are tailored to different sizes and server usages:

Advertisement
  • my-small.cnf: Suitable for systems with limited resources or for small testing and development.
  • my-medium.cnf: Designed for servers with medium memory counts, around 128MB to 512MB.
  • my-large.cnf: Designed for servers with larger memory, typically around 1GB to 2GB.
  • my-huge.cnf: For servers with very large resources, such as more than 2GB of memory.

Choosing a Configuration Based on Hardware Capacity

Each server has a different hardware capacity, and the MySQL configuration must be tailored to that capacity to ensure optimal performance. Some aspects to consider when adjusting configurations based on hardware are:

Memory (RAM):

Adjust the size of the buffer and cache to match the amount of memory available. For example, the allocation of InnoDB pool buffers and MyISAM key buffers should be adjusted so as not to exceed the physical memory capacity, to avoid swapping that can degrade performance.

CPU:

The configuration of MySQL threads and processes must be adjusted to the number of CPU cores. Using multithreading wisely can help improve performance on multi-core systems.

Disk I/O:

Choose settings that optimize disk usage, especially if you’re using a mechanical disk. For example, the size of the file logs and buffer logs for InnoDB should be adjusted to reduce the frequency of disk writes and improve performance.

32-bit vs 64-bit architecture:

64-bit servers can handle more memory than 32-bit servers, so settings such as InnoDB buffer pools can be larger on 64-bit servers.

2. Managing Memory Usage

Getting to Know the Controllable Memory Limits

Memory usage settings in MySQL are essential to ensure that the server can operate efficiently without experiencing memory shortages or overloads that can lead to swapping and performance degradation. Some memory limitations that need to be known and can be controlled include:

Physical and Virtual Memory:

The server must be configured so that the memory used by MySQL does not exceed the available physical memory to avoid using virtual memory that can slow down performance.

Memory Limitations by Operating System:

The operating system has limitations on the memory that can be used by MySQL processes. On 32-bit systems, this limit is usually around 4GB, while on 64-bit systems, the limit is much higher, allowing for larger memory usage.

Buffer and Cache:

MySQL has several configurable buffers and caches, such as InnoDB pool buffers, MyISAM key buffers, and query caches. This setting should be adjusted to the available memory capacity.

Setting Memory for Connections and Queries

Memory usage in MySQL is not only affected by buffers and caches but also by the number of connections and the type of queries executed. Some of the steps to set up memory for connections and queries are:

Thread Concurrency:

Sets the number of threads that can run simultaneously. The innodb_thread_concurrency setting can be used to limit the number of InnoDB threads running concurrently, reducing competition for memory resources.

Memory Per Connection:

Each connection to MySQL requires a certain amount of memory to execute queries. Parameters such as sort_buffer_size, join_buffer_size, and read_buffer_size can be configured to determine the amount of memory used by a particular query operation. For example, sort_buffer_size specifies the memory used for the sorting operation, and join_buffer_size specifies the memory for the join operation.

Query Cache:

Enabling and configuring query caching can help reduce the load on the server by storing the results of frequently executed queries. The query_cache_size parameter specifies the total size of the cache, while query_cache_limit limits the maximum size of query results that can be cached.

InnoDB Buffer Pool:

For InnoDB tables, the buffer pool is the main memory area used to store data and indexes. innodb_buffer_pool_size settings should be adjusted to the amount of physical memory available to ensure that read and write operations can be performed efficiently without accessing the disk frequently.

3. Setting Memory Usage for Connections

Calculating the Memory Required for Connection

Managing the memory used for each MySQL connection is essential to ensure that the server can efficiently handle multiple connections without running out of memory. Each connection to a MySQL server uses a specific amount of memory that varies depending on the configuration and the type of query being executed. Some memory components that need to be taken into account for each connection include:

  • Thread Stack: Each connection requires a certain amount of memory for the thread stack, which is determined by the thread_stack parameters.
  • Sort Buffer: The memory used for the sequencing operation is determined by the parameters sort_buffer_size.
  • Join Buffer: The memory used for the join operation is determined by the join_buffer_size parameter.
  • Read Buffer: The memory used for read operations from the disk is determined by the parameters of read_buffer_size.

To calculate the total memory required for each connection, you can add up the values from the buffers and stacks used. For example:

Total Memory per Connection = thread_stack + sort_buffer_size + join_buffer_size + read_buffer_size

If your MySQL server is expected to handle many connections simultaneously, you must ensure that the total memory required for all connections does not exceed the physical memory capacity of the server. For example, if you expect 100 simultaneous connections, then:

Total Memory for All Connections =100 × Total Memory per Connection

Setting Memory for Sort Buffers and Temporary Tables

Sorting operations and the use of temporary tables can require a lot of memory, especially if the queries being executed are complex or involve large datasets. Optimizing these settings can improve query performance and memory usage efficiency.

Sort Buffer Size:

The sort_buffer_size parameter specifies the size of the buffer used for the sorting operation. This memory is allocated per connection that performs the sorting. A larger buffer size can improve sorting performance, but it also increases memory consumption. Finding the right balance is key to optimization. For example, you might start small and gradually increase it while monitoring performance.

Provisional Table:

Operations that require temporary tables, such as the GROUP BY operation or the use of aggregate functions, use memory defined by the tmp_table_size and max_heap_table_size parameters. If the size of the temporary table exceeds the specified value, the table will be stored on disk, which can slow down performance. Therefore, setting a large enough value for this parameter can help maintain high performance.

  • tmp_table_size: Specifies the maximum size of temporary tables created in memory.
  • max_heap_table_size: Specifies the maximum size of HEAP tables (in-memory tables).

Adjusting these values according to workload and memory availability can significantly improve memory usage efficiency and query performance.

4. Setting Memory Usage for Queries

Calculating the Memory Required for Query Execution

To optimize memory usage during query execution, it’s important to understand how much memory is required by the query being executed. Some parameters that affect memory usage for query execution include:

  • join_buffer_size: Used when MySQL performs join operations without an index.
  • sort_buffer_size: Used for sorting operations that require a memory buffer.
  • read_buffer_size: The buffer used for table scanning operations.
  • read_rnd_buffer_size: Used after sorting to read rows in the order that has been sorted.
  • tmp_table_size and max_heap_table_size: Specifies the maximum size of the temporary table created in memory.

To calculate the total memory required for query execution, you need to consider the type and complexity of the query being executed as well as the parameters that affect memory usage. For example, a query that involves a large joint operation or sorting on a large dataset will require more memory than a simple query.

Suppose you have multiple queries that require a join buffer and a sort buffer, then the required memory can be calculated as follows:

Total Memory for Query Execution = join_buffer_size + sort_buffer_size + read_buffer_size + read_rnd_buffer_size

If you have many queries running at the same time, then the total memory required will be a multiple of the memory per query.

Managing Memory to Avoid Memory Shortages

To avoid memory shortages during query execution, it is important to adjust memory parameters wisely and ensure that the total memory usage does not exceed the physical memory capacity of the server. Some steps that can be taken to effectively organize memory include:

Adjusting Memory Parameters:

Gradually adjust parameters such as join_buffer_size, sort_buffer_size, read_buffer_size, and tmp_table_size while monitoring memory usage and server performance. Make sure these values are not so large that they cause memory shortages, but they are also large enough to ensure good performance.

Continuous Monitoring and Adjustment:

Regularly monitor memory usage and query performance using monitoring tools such as MySQL Performance Schema or third-party monitoring tools. Based on monitoring data, adjust memory parameters to optimize performance and prevent memory shortages.

Efficient Query Settings:

Optimize queries to reduce memory usage, such as using the right indexes, avoiding unnecessary join operations, and limiting the amount of data processed at a time. A well-optimized query will require less memory and run faster.

Maximum Connection Limitations:

Set a maximum limit on the number of simultaneous connections using max_connections parameters. This will help ensure that the total memory usage does not exceed the physical memory capacity of the server.

5. Setting Up Memory for the Operating System

Calculating the Memory Required for the Operating System

Before allocating memory to MySQL, it is important to ensure that the operating system (OS) has enough memory to perform its basic tasks. If the operating system is low on memory, this can lead to serious performance issues, including swapping memory to disk, which can drastically slow down MySQL performance.

To calculate the memory required for the operating system, consider the following factors:

OS Base Memory:

The operating system requires a basic amount of memory to run core processes and services. On Linux systems, this typically ranges from 200MB to 1GB, depending on the distribution and configuration.

Additional Processes and Services:

If the server is running additional services such as web servers (Apache/Nginx), application servers, or monitoring services, additional memory should be allocated to them.

OS Buffer and Cache:

Operating systems use buffers and caches to improve I/O performance. For example, Linux uses file caching to store frequently accessed data. This requires sufficient additional memory.

In general, a good rule of thumb is to leave about 20-25% of the total physical memory for the operating system and other services. For example, on a server with 16GB of RAM:

Memory for OS = 0.20 × 16GB = 3.2GB

Avoiding Virtual Memory to Disk Swapping

Swapping is the process by which data from physical memory is moved to disk when physical memory is full. This can be very detrimental to MySQL performance because disk access is much slower than memory access. To avoid swapping, the following steps can be taken:

Adjusting Swappiness:

On Linux systems, the swappiness parameter determines how aggressively the kernel will use swaps. The swappiness value can be adjusted to reduce the use of swaps. Lower values (e.g., 10) reduce the system’s tendency to use swaps:

sudo sysctl vm.swappiness=10

To make these changes permanent, add them to /etc/sysctl.conf:

vm.swappiness=10

Memory Usage Monitoring:

Use monitoring tools to keep an eye on system memory usage and swaps. Tools like htop, free, or graphics monitoring like Grafana can help monitor memory usage in real time.

Allocating Memory Wisely for MySQL:

Make sure that the MySQL configuration does not use all of the physical memory. Leave enough memory for the operating system and other services. For example, if you have 16GB of RAM, and have calculated that the OS needs about 3.2GB, then allocate about 12-13GB for MySQL.

MySQL Memory Usage Optimization:

As explained earlier, adjust MySQL memory parameters such as innodb_buffer_pool_size, key_buffer_size, and query_cache_size to ensure that the total MySQL memory usage does not exceed the available memory.

6. Setting Memory for Cache

Cache is an important component in MySQL that helps improve performance by storing frequently accessed data in memory, thereby reducing the need to access slower disks. By using caching effectively, you can improve query speed and reduce the load on the storage system. The two main types of caches used in MySQL are MyISAM cache and InnoDB cache.

Setting Up Cache for MyISAM and InnoDB

MyISAM Cache

MyISAM is an older MySQL storage engine and uses key_buffer_size as the main parameter to set the size of its index cache. This parameter is very important because cached indexes can be accessed much faster than indexes that need to be read from disk.

key_buffer_size: Specifies the cache size for the MyISAM index. Setting this size too small can lead to frequent slow disk access while setting it too large can leave a bit of memory for other needs. As a general rule, key_buffer_size should be set between 25-30% of the total physical memory on a server that only uses MyISAM.

Example settings in the MySQL configuration file (my.cnf):

[mysqld]

key_buffer_size = 4G

InnoDB Cache

InnoDB is the default and most widely used storage engine in MySQL. InnoDB uses innodb_buffer_pool_size to set up the main cache that stores the data and indexes of InnoDB tables.

innodb_buffer_pool_size: Specifies the size of the buffer pool used to store data and indexes. This setting is critical to InnoDB’s performance because frequently accessed data is stored in a buffer pool, reducing disk access. As a general rule, innodb_buffer_pool_size should be set between 60-80% of the total physical memory on a server that only uses InnoDB.

Example settings in the MySQL configuration file (my.cnf):

[mysqld]

innodb_buffer_pool_size = 12G

innodb_buffer_pool_instances: If the buffer pool is large (more than 1GB), you can split it into multiple instances to increase the concurrency. For example, if innodb_buffer_pool_size is set to 12GB, you can split it into 4 instances of 3GB each:

[mysqld]

innodb_buffer_pool_size = 12G

innodb_buffer_pool_instances = 4

Query Cache (General)

MySQL also has a query cache that stores the results of frequently repeated queries to speed up the execution time of subsequent queries. However, in the latest version, the query cache is considered obsolete and has been removed in MySQL 8.0 due to performance issues in environments with a lot of writes.

query_cache_size: If you are using an older version of MySQL, you can set the cache query size with this parameter. However, we recommend using app-level caching or cache proxies for better management.

[mysqld]

query_cache_size = 256M

7. Setting Up Cache for MyISAM

Setting the Buffer Key Size for MyISAM

The buffer key (key_buffer_size) is the primary cache used by the MyISAM storage engine to store indexes. Proper setting of the key_buffer_size is essential to ensure optimal performance because frequently accessed indexes are stored in a buffer, reducing the need for slower disk access.

key_buffer_size: The size of the buffer key determines how much memory is allocated to store the MyISAM index. This setting should be adjusted based on the amount of physical memory available and the amount of data accessed periodically. In general, if your server uses MyISAM exclusively, you can allocate between 25-30% of the total physical memory to key_buffer_size.

Example settings in the MySQL configuration file (my.cnf):

[mysqld]

key_buffer_size = 4G

This customization allows MySQL to store more indexes in memory, which can speed up frequently executed searches and queries.

Using Multiple Key Buffers for MyISAM

On some versions of MySQL, it is possible to use multiple key caches for MyISAM. This can be useful in situations where you want to allocate different caches to different tables or groups of tables, thus improving performance in a more controlled and granular way.

Setting up Multiple Key Buffers:

You can create multiple key buffers and allocate specific tables to those buffers. This is done by using SQL commands such as CACHE INDEX and LOAD INDEX INTO CACHE. However, note that this feature is used less frequently and may not be supported in all versions of MySQL.

Example settings for using multiple key buffers:

— Create additional key buffers

SET GLOBAL keycache1.key_buffer_size=2G;

SET GLOBAL keycache2.key_buffer_size=2G;

— Allocating tables to specific key buffers

CACHE INDEX tabel1, tabel2 IN keycache1;

CACHE INDEX tabel3 IN keycache2;

— Loading indexes into the cache

LOAD INDEX INTO CACHE tabel1, tabel2, tabel3;

This way, you can allocate different buffer keys to different tables, allowing you to optimize memory usage according to the access patterns specific to those tables.

8. Setting Up the Cache for InnoDB

Setting the Buffer Pool Size for InnoDB

To improve InnoDB’s performance, one of the important steps is to set the right buffer pool size. Here are the steps you can take:

1. Determine the Appropriate Buffer Pool Size:

  • The ideal buffer pool size for InnoDB is typically around 80% of the server’s physical memory capacity. However, you can use more than that if the server has a lot of memory.
  • Example: innodb_buffer_pool_size = 80% of total physical memory.

2. Set the Buffer Pool Size Based on Needs:

  • If your server has a lot of memory, you can increase the size of the pool buffer by 90% or more.
  • Example: innodb_buffer_pool_size = 90% of total physical memory.

3. Using InnoDB to Improve Performance:

  • InnoDB is designed to optimize performance by using a large buffer pool to store data and indexes.
  • By using InnoDB, you can reduce disk access and improve query performance.

Using InnoDB to Improve Performance

To use InnoDB effectively and improve performance, you can follow these steps:

1. Setting the Right InnoDB Parameters:

  • Make sure InnoDB parameters such as innodb_buffer_pool_size, innodb_log_file_size, and innodb_flush_log_at_trx_commit are tailored to your server’s needs.
  • Example: innodb_buffer_pool_size = 80% of total physical memory.

2. Using Buffer Pools to Improve Performance:

  • Use a buffer pool to store data and indexes, which can reduce disk access and improve query performance.
  • Example: innodb_buffer_pool_size = 80% of total physical memory.

3. Optimizing Performance by Using InnoDB:

  • Use InnoDB to optimize performance by using a large buffer pool to store data and indexes.
  • Example: innodb_buffer_pool_size = 80% of total physical memory.

9. Testing and Monitoring

Using Tools to Measure Cache Performance

To measure cache performance, you can use several tools provided by MySQL. Here are some ways to measure cache performance:

1. Using SHOW STATUS and SHOW VARIABLES:

You can use the SHOW STATUS and SHOW VARIABLES commands to measure cache performance. Example:

SHOW STATUS LIKE 'Key_reads';

SHOW STATUS LIKE 'Key_read_requests';

SHOW STATUS LIKE 'Key_blocks_unused';

SHOW STATUS LIKE 'key_buffer_size';

2. Using innotop:

Innotop is a tool that can help you measure the performance of InnoDB in more detail. Example:

innotop -i 10 --status

3. Using the mysqladmin command:

You can use the mysqladmin command to measure cache performance continuously. Example:

mysqladmin extended-status -r -i 10 | grep Key_reads

Calculating the Cache Hit Rate and Buffer Percentage Used

To calculate the cache hit ratio and buffer percentage used, you can use some equations provided by MySQL. Here are some ways to calculate it:

1. Calculating the Cache Hit Rate:

The cache hit ratio can be calculated using the equation:

Cache hit ratio = 10 - ((Key_reads *  100) /  Key_read_requests)

Example:

mysql> SHOW STATUS LIKE 'Key_reads';
+---------------+--------+
| Variable_name | Value  |
+---------------+--------+
| Key_reads     | 100    |
+---------------+--------+
mysql> SHOW STATUS LIKE 'Key_read_requests';
+-------------------+--------+
| Variable_name     | Value  |
+-------------------+--------+
| Key_read_requests | 1000  |
+-------------------+--------+
mysql> SELECT 100 - ((100 * 100) / 1000);
+-----------------------+
| 99.00                 |
+-----------------------+

2. Calculating the Percentage of Buffers Used:

The percentage of buffers used can be calculated using the equation:

Percentage of buffer in use = 100 – ((Key_blocks_unused * key_cache_block_size) * 100 / key_buffer_size)

Example:

mysql> SHOW STATUS LIKE 'Key_blocks_unused';
+-------------------+--------+
| Variable_name     | Value  |
+-------------------+--------+
| Key_blocks_unused  | 1000  |
+-------------------+--------+
mysql> SHOW VARIABLES LIKE 'key_buffer_size';
+-----------------------+--------+
| Variable_name        | Value  |
+-----------------------+--------+
| key_buffer_size      | 1024M |
+-----------------------+--------+
mysql> SELECT 100 - ((1000 * 1024 * 1024) / (1024 * 1024));
+-----------------------+
| 99.00                 |
+-----------------------+

10. Conclusion

MySQL server optimization is the key to achieving high performance and efficiency in database management. By optimizing server configurations, buffer pools, and caches, you can reduce latency, improve data access speeds, and optimize resource usage. These steps ensure that the server can better handle the workload and provide a faster response to the end user.

To improve the performance of a MySQL server, you need to take several strategic steps, including: Setting Up Cache and Buffer Pools, Conducting Testing and Monitoring, Optimizing Queries, and Implementing Effective Indexing

By implementing these steps, you can achieve optimal performance of your MySQL server and ensure that your system can handle the increasing demands efficiently.

Latest Articles