MySQL query cache optimization
1 Overview
Turn on the query cache of Mysql. When the same SQL statement is executed, the server will directly read the results from the cache. When the data is modified, the previous cache will become invalid. Tables that are frequently modified are not suitable for query cache.
2 Operation process
1. The client sends a query to the server;
2. The server first checks the query cache, and if it hits the cache, it immediately returns the result stored in the cache. Otherwise, enter the next stage;
3. The server side performs SQL analysis and preprocessing, and then the optimizer generates the corresponding execution plan;
4. MySQL calls the storage engine API to execute the query according to the execution plan generated by the optimizer ;
5. The result is returned to the client.
3 Query cache configuration
- Check whether the current MySQL database supports query caching:
SHOW VARIABLES LIKE 'have_query_cache';
mysql> SHOW VARIABLES LIKE 'have_query_cache';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| have_query_cache | YES |
+------------------+-------+
1 row in set (0.26 sec)
Represents that the current database supports query caching
- Check whether the query cache is enabled in MySQL:
mysql> SHOW VARIABLES LIKE 'query_cache_type';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| query_cache_type | OFF |
+------------------+-------+
1 row in set (0.01 sec)
Indicates that the query cache is not currently enabled
- View the occupied size of the query cache:
mysql> SHOW VARIABLES LIKE 'query_cache_size';
+------------------+----------+
| Variable_name | Value |
+------------------+----------+
| query_cache_size | 16777216 |
+------------------+----------+
It means that the current query cache occupies 16777216 bytes, which is about 1.5MB. If the cache is too small, you can change the value of query_cache_size to increase the size of the query cache.
- View the state variables of the query cache:
mysql> SHOW STATUS LIKE 'Qcache%';
+-------------------------+----------+
| Variable_name | Value |
+-------------------------+----------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 16768680 |
| Qcache_hits | 0 |
| Qcache_inserts | 0 |
| Qcache_lowmem_prunes | 0 |
| Qcache_not_cached | 29 |
| Qcache_queries_in_cache | 0 |
| Qcache_total_blocks | 1 |
+-------------------------+----------+
The meaning of each variable is as follows:
parameter | meaning |
---|---|
Qcache_free_blocks | Query the number of free memory blocks in the cache |
Qcache_free_memory | The amount of memory available for query cache |
Qcache_hits | Query cache hits |
Qcache_inserts | Number of queries added to the query cache |
Qcache_lowmen_prunes | The number of queries deleted from the query cache due to insufficient memory |
Qcache_not_cached | The number of non-cached queries (cannot be cached or not cached due to the query_cache_type setting) |
Qcache_queries_in_cache | Number of queries registered in the query cache |
Qcache_total_blocks | Total number of blocks in the query cache |
4 Turn on query cache
MySQL's query cache is turned off by default, and you need to manually configure the parameter query_cache_type to enable query cache. There are three possible values for query_cache_type:
value | meaning |
---|---|
OFF or 0 | Query cache function is off |
ON or 1 | When the query cache function is turned on, the result of SELECT will be cached if it meets the caching conditions. Otherwise, it will not be cached, and SQL_NO_CACHE will be explicitly specified and not cached |
DEMAND or 2 | The query cache function is performed on demand, and only SELECT statements that explicitly specify SQL_CACHE will be cached; others will not be cached |
How to set the value of query_cache_type, here we need to modify the MySQL configuration file
blogger's Ubuntu (Linux operating system) version to 16.04, mysql version to 5.7. You need to enter /etc/mysql/mysql.conf.d to modify the configuration file mysqld.cnf to
add the following content
and then you need to restart the MySQL service
Log in to MySQL
again, you can then query whether the MySQL query cache is enabled
After the configuration is complete, restart the service to take effect;
Then you can execute the SQL statement on the command line for verification, execute a relatively time-consuming SQL statement, and then execute it a few more times to check the execution time of the next few times; get the cache hits of the query cache to determine whether to go Query the cache.
We can test. We once built a table tb_item with 2.5 million pieces of data.
mysql> select count(*) from tb_item;
+----------+
| count(*) |
+----------+
| 2499695 |
+----------+
1 row in set (8.57 sec)
mysql> select count(*) from tb_item;
+----------+
| count(*) |
+----------+
| 2499695 |
+----------+
1 row in set (0.00 sec)
As you can see, the first execution of 8s, the second execution of the same SQL statement, only need 0s
so that we can verify that the query cache is indeed enabled and effective.
We can see the cache status, the number of hits has been 1, and the number of times added to the cache is 1 (because the same SQL statement is only added in the first query)
5 Query cache SELECT option
Two options related to query caching can be specified in the SELECT statement:
SQL_CACHE: If the query result is cacheable and the value of the query_cache_type system variable is ON or DEMAND, the query result is cached.
SQL_NO_CACHE: The server does not use query cache. It neither checks the query cache, nor does it check whether the results are cached, nor does it cache the query results.
Note: When the value of the query_cache_type system variable is ON, it will be cached even if SQL_CACHE is not added, and the value of the query_cache_type variable is DEMAND. Only when SQL_CACHE is specified, the cache will be used.
The first two rows of the tb_item table are as follows
mysql> select * from tb_item limit 2;
+----+------------+----------+-------+------------+--------+------------+---------------------+---------------------+
| id | title | price | num | categoryid | status | sellerid | createtime | updatetime |
+----+------------+----------+-------+------------+--------+------------+---------------------+---------------------+
| 1 | 货物1号 | 33494.85 | 365 | 0 | 1 | 5435343235 | 2019-04-20 22:37:15 | 2019-04-20 22:37:15 |
| 2 | 货物2号 | 5617.72 | 24060 | 0 | 1 | 5435343235 | 2019-04-20 22:37:15 | 2019-04-20 22:37:15 |
+----+------------+----------+-------+------------+--------+------------+---------------------+---------------------+
2 rows in set (0.04 sec)
We test the query (note that the previous statement has been placed in the cache, and the corresponding state value will change)
mysql> select title,sellerid from tb_item where id=1;
+------------+------------+
| title | sellerid |
+------------+------------+
| 货物1号 | 5435343235 |
+------------+------------+
1 row in set (0.00 sec)
mysql> show status like 'Qcache%';
+-------------------------+----------+
| Variable_name | Value |
+-------------------------+----------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 16764840 |
| Qcache_hits | 1 |
| Qcache_inserts | 3 |
| Qcache_lowmem_prunes | 0 |
| Qcache_not_cached | 3 |
| Qcache_queries_in_cache | 3 |
| Qcache_total_blocks | 8 |
+-------------------------+----------+
8 rows in set (0.00 sec)
Explain that this statement has also been added to the cache
When I don’t want to do caching, we need to add SELECT_NO_CACHE after select
mysql> select SQL_NO_CACHE title,sellerid from tb_item where id=2;
+------------+------------+
| title | sellerid |
+------------+------------+
| 货物2号 | 5435343235 |
+------------+------------+
1 row in set, 1 warning (0.00 sec)
mysql> show status like 'Qcache%';
+-------------------------+----------+
| Variable_name | Value |
+-------------------------+----------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 16764840 |
| Qcache_hits | 1 |
| Qcache_inserts | 3 |
| Qcache_lowmem_prunes | 0 |
| Qcache_not_cached | 4 |
| Qcache_queries_in_cache | 3 |
| Qcache_total_blocks | 8 |
+-------------------------+----------+
8 rows in set (0.03 sec)
The value of Qcache_inserts is still 3, indicating that it is not cached.
6 Query cache invalidation
We have improved before, when the value of query_cache_type is set to 1, it will cache the results of select statements that meet the conditions. The reason is because in some cases, the query cache will be invalid.
1) In the case of inconsistent SQL statements, in order to hit the query cache, the query SQL statements must be completely consistent.
SQL1 : select count(*) from tb_item;
SQL2 : Select count(*) from tb_item;
Only the case is different.
mysql> select count(*) from tb_item;
+----------+
| count(*) |
+----------+
| 2499695 |
+----------+
1 row in set (0.00 sec)
mysql> Select count(*) from tb_item;
+----------+
| count(*) |
+----------+
| 2499695 |
+----------+
1 row in set (2.02 sec)
2) When there are some uncertainties in the query statement, it will not be cached. Such as: now(), current_date(), curdate(), curtime(), rand(), uuid(), user(), database(). The results obtained by these functions are different each time.
SQL1 : select * from tb_item where updatetime < now() limit 1;
SQL2 : select user();
SQL3 : select database();
3) Do not use any table query statements.
For example, select a constant select'hello';
select 'A';
4) When querying tables in mysql, information_schema or performance_schema system databases, the query cache will not be used.
MySQL system database includes mysql, information_schema or performance_schema
select * from information_schema.engines;
5) Queries executed within the body of stored functions, triggers or events.
6) If the table changes, all cache queries using the table will become invalid and deleted from the cache. This includes MERGE
queries that use tables mapped to changed tables. A table can be changed by many types of statements, such as INSERT, UPDATE, DELETE, TRUNCATE TABLE, ALTER TABLE, DROP TABLE, or DROP DATABASE.
mysql> Select count(*) from tb_item;
+----------+
| count(*) |
+----------+
| 2499695 |
+----------+
1 row in set (0.00 sec)
mysql> update tb_item set title='test1' where id=5;
Query OK, 1 row affected (0.05 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> Select count(*) from tb_item;
+----------+
| count(*) |
+----------+
| 2499695 |
+----------+
1 row in set (1.23 sec)
mysql> Select count(*) from tb_item;
+----------+
| count(*) |
+----------+
| 2499695 |
+----------+
1 row in set (0.00 sec)