Databases play a critical role in any application's performance. MySQL database is no exception. It is therefore important to understand the many ways that database tuning, design, and configuration can help improve your application’s performance. Below are some ways that MySQL can be optimized to achieve optimal performance.
Query tuning
Database performance tuning starts from the application. How the application translates the business requirements to database queries makes a big difference on the complexity and efficiency of the application. The real measure of performance is how efficiently each database instance contributes to the business needs.
Schema design
How entities and relationships are defined in a relational database determines how straightforward or complex a response will be to a database query. Also, how the primary key and secondary indexes are defined plays an important role.
Server configuration
Server configuration is responsible for optimizing and maximizing the utilization of system resources. The system resources are the core processing unit (CPU) cores, memory on the physical machine or virtual machine (VM), the underlying storage system, and the network.
Dynamic server tuning
Continuous monitoring, optimizing, and performance tuning to adapt database workloads for real world dynamics.
This article focuses on query tuning. The rest of the topics would be covered in subsequent articles.
We often start the query tuning process by looking at the database query. A better way would be to start with evaluating how efficiently has the business requirement been translated into a database query. The interpretation and processing of a business need to a query determines how small or large the cost would be.
The first step is to prioritize queries to be optimized:
These two categories need to be optimized during the database schema design.
A transaction is a logical unit where all contained statements would either commit fully or roll back. Transaction is the feature that provides atomicity, consistency, isolation and durability (ACID) for MySQL.
In InnoDB, the storage engine for MySQL, all user activities occur inside a transaction. By default, autocommit mode is enabled, which means that each SQL statement forms a single transaction on its own. To perform a multiple-statement transaction when autocommit is enabled, start the transaction explicitly with START_TRANSACTION or BEGIN and end it with COMMIT or ROLLBACK. If autocommit mode is disabled, the session always has a transaction open until a COMMIT or ROLLBACK ends it and starts a new one.
The best practice with transactions is to keep them as short as possible. This is because long transactions have several downsides as outlined further in this article.
1. Prolonged lock contentions, which cause slower queries and potential query failures
2. Degraded server performance due to large amount of undo logs
3. Increased disk usage
4. Prolonged shutdown time
5. Prolonged crash recovery time
Queries could be captured either on the application side or the database side.
It is good development practice to log database queries and query execution time. Application side logging makes it easy to evaluate the effectiveness and efficiency of the queries in their business context. For example, users may log every query’s response time or log response time for certain functionalities. This is also an easy way to get total execution time for multi-statement transactions.
In addition, the query response time measured from application side logging is an end to end measurement, including network time. It complements query execution time logged from the database and makes it easy to identify whether the issue is with the network issue or the database.
Cloud SQL MySQL Query insights
The Cloud SQL Query insights tool enables query capturing, monitoring, and diagnosis.
Query insights makes it easy to find the top queries based on execution time and execution frequency.
The tool has filtering options such as time range, database, user account, and client address. It has graphs to show the CPU usage, and breakdown on IO and lock waits. The “Top queries and tags” table lists the top queries by execution time with the queries being normalized. Besides the execution time, it includes stats on “avg rows scanned” and “avg rows returned” which give insights to query efficiency.
Please refer to the documentation to see all that it offers and how to enable it.
Use performance_schema
On Cloud SQL for MySQL, performance_schema feature is enabled by default for MySQL 8.0.26 and higher versions with 15GB+ memory. Enabling or disabling it requires instance restart.
When performance_schema=ON, the query statement instruments are enabled by default. The sys.statement_analysis table gives aggregated statistics for normalized queries. It answers questions such as:
If you use MySQL Workbench, it has performance schema reports based on sys view. The report has a section on “High Cost SQL Statements,” which provides insights on query performance.
Use slow log + tooling
The slow log captures all the queries running longer than the long_query_time. It also logs query execution time, lock time, data rows examined and data rows sent. The additional execution statistics makes it a preferred candidate to analyze the database queries than using the general log.
It is a good practice to have slow log enabled. Normally, the long_query_time should be kept at a reasonable threshold to capture queries that you intend to look at and optimize.
log_output=FILE
slow_query_log=ON
long_query_time=2
Once in a while, it is a good idea to set long_query_time=0 to capture all queries for a brief time and get an overview of query volume and performance.
There are tools, such as mysqldumpslow and pt-query-digest, which would extract query signatures and generate a report to show query statistics.
There are other third-party monitoring tools that generate reports on query statistics, such as Percona Monitoring and Management, SolarWinds Database Performance Monitor (previously VividCortex), and more.
After capturing the queries in transactions, the next step is to optimize them.
The EXPLAIN command provides the query execution plan and from 8.0.18, the EXPLAIN ANALYZE command would run a statement and produce EXPLAIN output along with timing from the execution.
The MySQL Query insight provides handy access to the EXPLAIN plan.
What do we look for in the output?
Session status variables could be used to obtain query execution details.
First, clear the session variables, then run the query and examine the counters. For example, the Handler_* status shows the data access pattern and row amount. The Created_* would show if a temporary table and/or on-disk temporary table is created. The Sort_* would show the number of sort merge passes and the number of rows sorted. More session variables are explained in the documentation.
The SHOW PROFILE statement provides query execution time by execution stage which could be helpful information as well.
Once the query execution plan is understood, there are multiple ways to influence and optimize it.
To optimize the server configuration for certain queries, it is highly recommended to use the session level variables instead of changing the global value that affects all sessions.
The frequently used session values are:
In summary, for query tuning, we talked about three aspects:
Start building on Google Cloud with $300 in free credits and 20+ always free products.