当前位置:   article > 正文

MySQL核心技术原理之:查询缓存与结果缓存_mysql缓存查询结果

mysql缓存查询结果

作者:禅与计算机程序设计艺术

1.简介

随着互联网的蓬勃发展,网站流量越来越大,网站的数据库访问频率也越来越高,而对于数据库服务器来说,一次数据库请求所花费的时间也越来越长。为了解决这个问题,数据库系统设计者们提出了缓存技术,将数据库中的数据存储到内存中,这样就可以减少数据库的访问次数,加快响应速度。

查询缓存

查询缓存(Query Cache)是指当用户执行一条SQL语句时,首先在缓存中查找该条SQL是否已经被缓存过,如果已经被缓存,则直接从缓存中返回查询结果;否则,才会真正去数据库中进行查询。缓存的存在可以极大的提高数据库查询效率。因为相比于每次都需要去数据库中查询,缓存后只需从内存中获取结果,查询速度就会显著地提升。由于缓存通常是内存空间,因此查询缓存不能无限扩大,所以缓存过期、容量限制等方面都需要进行设置。

结果缓存

结果缓存(Result Cache)是指当用户执行一条SELECT语句(即查询语句)时,在查询结束之前,先把结果存放在内存中,直到下次再需要的时候再取出结果并返回给客户端。而非查询语句,例如INSERT、UPDATE、DELETE语句,一般不会执行结果缓存,也就是说即使对同一个表进行操作多次,其结果也不会被缓存起来。

2.基本概念术语说明

缓存击穿(Cache miss)

缓存击穿(cache-miss)是指某个热点数据被访问的情况,当某个数据出现在缓存中时,由于某种原因(如缓存过期或缓存空间不足),导致无法及时的更新到缓存中,从而导致缓存中没有该数据,然后用户再次访问该数据时,由于此时缓存中并没有该数据,因此只能从源数据库中读取。这种现象称之为缓存击穿。

缓存穿透(Cache penetration)

缓存穿透(cache-penetration)是指在缓存和数据库中都没有对应的数据,导致用户查询不到想要的数据。缓存穿透是一种性能问题,当缓存和数据库中都没有相应的数据时,查询将会向源数据库发送请求,这种请求量可能会很大,甚至造成系统崩溃。

缓存雪崩(Cache avalanche)

缓存雪崩(cache-avalanche)是指在某段时间内,缓存集体失效,所有请求都怼到数据库上。由于缓存过期时间短,刚好失效导致大量请求同时访问数据库,引起数据库压力过大,甚至宕机。

3.核心算法原理和具体操作步骤以及数学公式讲解

查询缓存实现

查询缓存的基本原理是将查询到的结果保存到缓存中,当下次有相同的查询请求时,就直接从缓存中返回查询结果,避免重新查询,提高查询效率。由于缓存是内存空间,不能无限扩大,因此系统设计者需要设置缓存的过期时间、大小限制等参数。

检查查询缓存

在执行SQL语句前,需要检查查询缓存中是否已经有缓存。如果缓存命中,则直接从缓存中读取查询结果;如果缓存丢失或者过期,则继续执行SQL语句并将查询结果保存到缓存中。

操作步骤

1.检查SQL文本是否与缓存中的SQL文本一致。如果一致,则表示命中缓存。
2.检查是否已经超过缓存过期时间。如果超过过期时间,则表示缓存过期,需要重新查询。
3.检查查询结果是否已经在缓存中。如果已经在缓存中,则直接从缓存中读取结果。
4.如果查询结果不存在缓存中,则执行SQL语句并将查询结果保存到缓存中。

SQL文本匹配规则

检查SQL文本匹配规则如下:

1.SQL文本完全匹配。
2.SQL文本与缓存中的SQL文本包含关系。

SQL文本完全匹配

SQL文本完全匹配时,比较SQL文本完全相同,才认为命中缓存。

SQL文本包含关系

SQL文本包含关系时,比较SQL文本是否包含缓存中的SQL文本。例如:

select * from user where id = 1;
  • 1

该SQL语句中包含id=1,因此可以命中以下缓存:

select * from user where id = 1 and name='test';
  • 1

缓存中包含name字段,但是该缓存不是针对上述SQL语句的,因此并不命中。

清空查询缓存

当修改数据库中的数据时,如果已经命中的缓存失效,则需要清除掉该缓存,以保证数据的最新性。

操作步骤

1.删除对应的缓存项。
2.刷新缓存中的最近使用列表。
3.如果缓存已满,则清除最近最久未使用的数据。

删除对应的缓存项

当修改数据库的数据时,要删除对应的缓存项。具体做法是,首先根据SQL语句生成唯一的key值,然后删除对应的缓存项即可。

刷新缓存中的最近使用列表

缓存中的数据有两种类型:热点数据(经常访问的数据)和冷数据(不经常访问的数据)。维护最近使用的列表,能够快速淘汰缓存中不需要的数据,以节约内存。

刷新最近使用列表的方式有两种:

1.定期扫描缓存,检查哪些数据最近被访问,并将其移到列表头部。
2.当有新数据加入缓存时,自动添加到列表尾部。

如果缓存已满

当缓存满了之后,需要清除掉最近最久未使用的数据,以腾出缓存空间。具体做法是,首先按最近最久未使用排序,清除最后的一部分数据;也可以选择优先级低的缓存项,将其淘汰掉。

结果缓存实现

结果缓存的基本原理是将查询结果保存到内存中,当下次需要该结果时,就直接从缓存中返回结果,而不是重新执行查询,提高查询效率。

设置结果缓存

设置结果缓存一般通过启动参数完成,比如mysqld --query_cache_type=ON 或 my.ini 中的 query_cache_type 参数。

查找查询缓存

在执行查询语句前,首先检查查询缓存中是否已经有缓存。如果查询缓存已经存在,则直接从缓存中返回查询结果;如果查询缓存不存在,则继续执行查询语句并将查询结果保存到缓存中。

操作步骤

1.检查SQL文本是否与缓存中的SQL文本一致。如果一致,则表示命中缓存。
2.检查缓存中是否已经有查询结果。如果有,则直接返回结果。
3.如果缓存中没有查询结果,则执行SQL语句并将查询结果保存到缓存中。

SQL文本匹配规则

检查SQL文本匹配规则如下:

1.SQL文本完全匹配。
2.SQL文本与缓存中的SQL文本包含关系。

SQL文本完全匹配

SQL文本完全匹配时,比较SQL文本完全相同,才认为命中缓存。

SQL文本包含关系

SQL文本包含关系时,比较SQL文本是否包含缓存中的SQL文本。例如:

select * from user where id = 1;
  • 1

该SQL语句中包含id=1,因此可以命中以下缓存:

select * from user where id = 1 and name='test';
  • 1

缓存中包含name字段,但是该缓存不是针对上述SQL语句的,因此并不命中。

4.具体代码实例和解释说明

查询缓存案例

查询缓存案例模拟一个数据库系统,其中有两个表userproduct。为了演示查询缓存的效果,假设设置了查询缓存和热点数据缓存。

-- 创建表
create table if not exists `user`(
  id int primary key auto_increment,
  username varchar(20),
  email varchar(50) unique key
);

create table if not exists `product`(
  id int primary key auto_increment,
  product_name varchar(20),
  price decimal(8,2),
  create_time datetime default current_timestamp
);

-- 插入测试数据
insert into user (username,email) values ('Alice','<EMAIL>');
insert into user (username,email) values ('Bob','<EMAIL>');
insert into user (username,email) values ('Charlie','<EMAIL>');

insert into product (product_name,price) values ('iPhone',7999.99);
insert into product (product_name,price) values ('MacBook Pro',14999.99);
insert into product (product_name,price) values ('iPad Air',6999.99);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

查询缓存案例分析

为了验证查询缓存的效果,我们进行一下操作:

# 第一次查询,缓存命中,热点数据缓存命中
mysql> select * from user where email='<EMAIL>';
+----+------------+--------------+---------------------+
| id | username   | email        | password            |
+----+------------+--------------+---------------------+
|  2 | Charlie    | <EMAIL> | xxxxxxxxxxxxxxxxxxxx |
+----+------------+--------------+---------------------+

# 第二次查询,缓存命中,热点数据缓存命中
mysql> select * from user where email='<EMAIL>';
+----+------------+----------------------+-------------+
| id | username   | email                | password    |
+----+------------+----------------------+-------------+
|  1 | Alice      | <EMAIL>       | xxxxxxxxxxx |
+----+------------+----------------------+-------------+

# 执行DML语句
mysql> update user set username='Tom' where email='<EMAIL>';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

# 第三次查询,缓存失效,热点数据缓存命中
mysql> select * from user where email='<EMAIL>';
+----+----------+-----------------+-------------+
| id | username | email           | password    |
+----+----------+-----------------+-------------+
|  2 | Tom      | <EMAIL>  | xxxxxxxxxxx |
+----+----------+-----------------+-------------+

# 更新缓存
mysql> flush tables with read lock;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from user where email='<EMAIL>' limit 1 for update;
+----+------+-----------------+-------------+
| id | uid  | email           | password    |
+----+------+-----------------+-------------+
|  2 |    1 | tom@example.com | xxxxxxxxxxx |
+----+------+-----------------+-------------+

mysql> update user set username='Tom' where email='<EMAIL>';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

查询缓存案例总结

从上面的例子可以看出,在第二次查询时,查询结果已经被缓存,不会再去执行查询。而且在执行更新操作时,更新的是缓存中的数据,而不是直接去数据库中更新。缓存失效时,要将更新的数据写入缓存,因此效率更高。

结果缓存案例

结果缓存案例模拟一个微博系统,每隔十分钟更新一次话题排行榜。为了验证结果缓存的效果,我们进行一下操作:

# 没有开启结果缓存的情况下,运行查询,发现耗时较长
mysql> SELECT pid, COUNT(*) AS hot FROM t WHERE status=1 AND created_at BETWEEN DATE_SUB(NOW(), INTERVAL 1 HOUR) AND NOW() GROUP BY pid ORDER BY hot DESC LIMIT 10;
+------+-------+
| pid  | hot   |
+------+-------+
|    4 |    20 |
|    6 |    15 |
|    2 |    15 |
|    3 |    10 |
|    1 |    10 |
|    5 |     9 |
|   12 |     7 |
|   11 |     5 |
|   10 |     5 |
|    9 |     5 |
+------+-------+
20 rows in set (3.02 sec)

# 通过设置开启结果缓存的参数,运行查询,发现耗时较短
mysql> SET @old_sql_mode=@@sql_mode, sql_mode=(SELECT REPLACE(@@sql_mode,'NO_ENGINE_SUBSTITUTION',''));
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @max_stmt_cache:=@@max_statement_history;
Query OK, 0 rows affected (0.00 sec)

mysql> SET @@global.max_statement_history=2048;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT pid, COUNT(*) AS hot FROM t WHERE status=1 AND created_at BETWEEN DATE_SUB(NOW(), INTERVAL 1 HOUR) AND NOW() GROUP BY pid ORDER BY hot DESC LIMIT 10;
+------+-------+
| pid  | hot   |
+------+-------+
|    4 |    20 |
|    6 |    15 |
|    2 |    15 |
|    3 |    10 |
|    1 |    10 |
|    5 |     9 |
|   12 |     7 |
|   11 |     5 |
|   10 |     5 |
|    9 |     5 |
+------+-------+
10 rows in set (0.00 sec)

# 在第二个查询中,由于命中结果缓存,结果返回速度明显更快
mysql> SELECT pid, COUNT(*) AS hot FROM t WHERE status=1 AND created_at BETWEEN DATE_SUB(NOW(), INTERVAL 1 HOUR) AND NOW() GROUP BY pid ORDER BY hot DESC LIMIT 10;
+------+-------+
| pid  | hot   |
+------+-------+
|    4 |    20 |
|    6 |    15 |
|    2 |    15 |
|    3 |    10 |
|    1 |    10 |
|    5 |     9 |
|   12 |     7 |
|   11 |     5 |
|   10 |     5 |
|    9 |     5 |
+------+-------+
10 rows in set (0.00 sec)

# 使用SHOW STATUS命令查看结果缓存相关状态
mysql> SHOW STATUS LIKE '%Qcache%';
+-------------------------------------------+-------+
| Variable_name                             | Value |
+-------------------------------------------+-------+
| Qcache_free_memory                        | 11352 |
| Qcache_free_blocks                        | 0     |
| Qcache_total_blocks                       | 0     |
| Qcache_hits                               | 1     |
| Qcache_inserts                            | 1     |
| Qcache_not_cached                         | 2     |
| Qcache_queries_in_cache                   | 3     |
| Queries                                  | 1     |
| Qcache_lowmem_prunes                      | 0     |
| Questions                                | 21    |
| Com_select                                | 2     |
| Threads_running                           | 1     |
| Connections                              | 2     |
| Ssl_connections                           | 0     |
| Table_locks_waited                        | 0     |
| Innodb_buffer_pool_wait_free              | 2     |
| Innodb_data_read                          | 24    |
| Innodb_rows_read                          | 13    |
| Key_reads                                 | 0     |
| Open_tables                               | 21    |
| Qcache_deleted                            | 0     |
| Qcache_hitrate                            | 0.000 |
| Query_cache_size                          | 0     |
| Qcache_free_frag_pct                      | 100.00 |
| Created_tmp_disk_tables                   | 0     |
| Created_tmp_files                         | 0     |
| Bytes_received                            | 52640 |
| Uptime                                    | 117   |
| Max_used_connections                      | 1     |
| Threads_connected                         | 1     |
| Aborted_connects                          | 0     |
| Table_locks_immediate                     | 0     |
| Slave_open_temp_tables                    | 0     |
| Threads_created                           | 1     |
| Network_wait_timeout                      | 60    |
| Qcache_lowmem_prunes                      | 0     |
| Innodb_buffer_pool_bytes_data             | 67901 |
| Innodb_buffer_pool_pages_flushed          | 1     |
| Select_full_join                          | 0     |
| Created_tmp_tables                        | 0     |
| Qcache_queries_in_cache                   | 3     |
| Innodb_row_lock_current_waits             | 0     |
| Handler_commit                            | 0     |
| Handler_delete                            | 0     |
| Handler_prepare                           | 0     |
| Handler_read_first                        | 0     |
| Handler_read_key                          | 0     |
| Handler_read_next                         | 0     |
| Handler_read_prev                         | 0     |
| Handler_read_rnd                          | 0     |
| Handler_read_rnd_next                     | 0     |
| Handler_rollback                          | 0     |
| Handler_savepoint                         | 0     |
| Handler_savepoint_rollback                | 0     |
| Handler_update                            | 0     |
| Open_files                                | 4     |
| Table_open_cache_overflows                | 0     |
| Threads_cached                            | 1     |
| Prepared_stmt_count                       | 0     |
| Table_definition_size                     | 2501  |
| Table_open_cache_instances                | 11    |
| Table_open_cache_seconds                  | 117   |
| Bytes_sent                                | 11876 |
| COM_COMMIT                                | 0     |
| COM_DELETE                                | 0     |
| COM_INSERT                                | 0     |
| COM_PREPARE                               | 0     |
| COM_ROLLBACK                              | 0     |
| COM_REPLACE                               | 0     |
| COM_SELECT                                | 2     |
| COM_UPDATE                                | 0     |
| Innodb_data_fsyncs                        | 0     |
| Innodb_data_pending_fsyncs                | 0     |
| Innodb_os_log_fsyncs                      | 0     |
| Ssl_accepts                               | 0     |
| Ssl_accept_renegotiates                   | 0     |
| Ssl_client_connects                       | 0     |
| Ssl_connects                              | 0     |
| Ssl_ctx_verify_depth                      | 0     |
| Ssl_finished_accepts                      | 0     |
| Ssl_session_cache_hits                    | 0     |
| Ssl_session_cache_misses                  | 0     |
| Ssl_session_cache_modes                   | 0     |
| Ssl_ssl_ctx_verify_status                 | 0     |
| Ssl_writes                                | 0     |
| Version                                   | 5.7.25 |
| binlog_cache_disk_use                     | 0     |
| binlog_cache_use                          | 0     |
| connection_errors_accept                  | 0     |
| connection_errors_internal                | 0     |
| connection_errors_max_connections         | 0     |
| connection_errors_peer_address            | 0     |
| connection_errors_select                  | 0     |
| connection_errors_tcpwrap                 | 0     |
| connections                               | 1     |
| max_used_connections                      | 1     |
| open_files_limit                          | 1024  |
| qcache_free_blocks                        | 0     |
| qcache_free_memory                        | 11352 |
| qcache_hits                               | 2     |
| qcache_inserts                            | 2     |
| qcache_lowmem_prunes                      | 0     |
| qcache_not_cached                         | 2     |
| qcache_queries_in_cache                   | 5     |
| qcache_total_blocks                       | 0     |
| range_optimizer_max_mem_size              | 8388608 |
| slave_open_temp_tables                    | 0     |
| sort_merge_passes                         | 0     |
| sort_range                                | 0     |
| sort_rows                                 | 0     |
| sort_scan                                 | 0     |
| ssl_accepts                               | 0     |
| ssl_accept_renegotiates                   | 0     |
| ssl_callback_cache_hits                   | 0     |
| ssl_cipher                                | NULL  |
| ssl_client_connects                       | 0     |
| ssl_connect_renegotiates                  | 0     |
| ssl_ctx_verify_depth                      | 0     |
| ssl_ctx_verify_mode                       | 0     |
| ssl_default_timeout                       | 0     |
| ssl_finished_accepts                      | 0     |
| ssl_sess_accept                           | 0     |
| ssl_sess_accept_good                      | 0     |
| ssl_sess_accept_renegotiate               | 0     |
| ssl_sess_cache_full                       | 0     |
| ssl_sess_connect                          | 0     |
| ssl_sess_connect_renegotiate              | 0     |
| ssl_sess_miss                             | 0     |
| ssl_shutdowns                             | 0     |
| ssl_session_cache_hits                    | 0     |
| ssl_session_cache_misses                  | 0     |
| ssl_session_cache_mode                    | 0     |
| ssl_session_cache_overflows               | 0     |
| ssl_session_cache_size                    | 4096  |
| threads_cached                            | 1     |
| threads_connected                         | 1     |
| uptime                                    | 117   |
| wsrep_causal_reads                        | 0     |
| wsrep_cert_deps_distance                  | 0     |
| wsrep_cert_index_size                     | 0     |
| wsrep_cert_interval                       | 0     |
| wsrep_cluster_size                        | 1     |
| wsrep_cluster_state_uuid                  |      |
| wsrep_commit_oooe                         | 0     |
| wsrep_commit_window                       | 0     |
| wsrep_desync                              | 0     |
| wsrep_duplicated_cert_transactions        | 0     |
| wsrep_egress_queue_length                 | 0     |
| wsrep_flow_control_paused                 | OFF   |
| wsrep_flow_control_paused_ns              | 0     |
| wsrep_flow_control_recv                   | 0     |
| wsrep_flow_control_sent                   | 0     |
| wsrep_local_bf_aborts                     | 0     |
| wsrep_local_cert_failures                 | 0     |
| wsrep_local_commits                       | 0     |
| wsrep_local_recv_queue_avglen             | 0     |
| wsrep_local_recv_queue_minlen             | 0     |
| wsrep_local_send_queue_avglen             | 0     |
| wsrep_local_send_queue_minlen             | 0     |
| wsrep_local_state_comment                 |       |
| wsrep_local_state_transferred            | 0     |
| wsrep_protocol_version                    | 7     |
| wsrep_provider_name                       | InnoDB |
| wsrep_ready                               | ON    |
| wsrep_receive_queue_avglen                | 0     |
| wsrep_receive_queue_minlen                | 0     |
| wsrep_repl_data_bytes                     | 0     |
| wsrep_repl_keys                           | 0     |
| wsrep_repl_other_bytes                    | 0     |
| wsrep_repl_other_keys                     | 0     |
| wsrep_repl_simultaneous_reps              | 0     |
| wsrep_replicate_versions                  | 1     |
| wsrep_retries_count                       | 0     |
| wsrep_retry_errno                         | 0     |
| wsrep_rpl_thread_count                    | 0     |
| wsrep_sent_bytes                          | 11876 |
| wsrep_send_queue_avglen                   | 0     |
| wsrep_send_queue_minlen                   | 0     |
| wsrep_service_level                       | NULL  |
| wsrep_stalls                              | 0     |
| wsrep_startup_committed_transactions      | 0     |
| wsrep_startup_commit_position             | -1    |
| wsrep_startup_complete                    | ON    |
| wsrep_sync_queue_avglen                   | 0     |
| wsrep_sync_queue_minlen                   | 0     |
| wsrep_sync_source_index                   | -1    |
| wsrep_total_committed_batches             | 0     |
| wsrep_total_committed_snapshots           | 0     |
| wsrep_total_incoming_bytes                | 11876 |
| wsrep_total_incoming_transmissions        | 1     |
| wsrep_total_keys                          | 0     |
| wsrep_total_nonSkipped_rows               | 0     |
| wsrep_total_pack_bytes                    | 0     |
| wsrep_total_queued_bytes                  | 0     |
| wsrep_total_queued_rows                   | 0     |
| wsrep_total_received_bytes                | 0     |
| wsrep_total_received_msgs                 | 0     |
| wsrep_total_rows                          | 0     |
| wsrep_total_sent_bytes                    | 0     |
| wsrep_total_sent_msgs                     | 0     |
| wsrep_total_skipped_bytes                 | 0     |
| wsrep_total_vco_bytes                     | 0     |
| wsrep_view_queue_avglen                   | 0     |
| wsrep_view_queue_minlen                   | 0     +----+--------------------+-------------+---------+
        Total items shown: 87 out of 106
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273

从以上查询结果可以看出,开启结果缓存后的查询速度较前者提升明显。原因在于结果缓存能够命中缓存中保存的结果,避免了重复计算,加快查询速度。

5.未来发展趋势与挑战

热点数据的缓存

目前,MySQL查询缓存主要用于缓存查询语句的结果,以提高查询效率。如果想进一步提高查询缓存的应用范围,比如缓存整个表的查询结果,那么就会遇到热点数据的缓存问题。

热点数据的缓存问题是指某一段时间内,缓存命中率很高,缓存占用内存很多的问题。这种问题往往发生在有大量热点数据的环境下,比如电商网站日均订单量最大的几个小时、秒杀活动、秒杀商品购买人数最多的那段时间等。由于缓存命中率高,所以缓存占用内存很多,最终影响到了其他查询请求的响应时间。

解决热点数据的缓存问题,可以从以下几个方面着手:

1.利用Redis等分布式缓存技术。目前很多开源分布式缓存产品,都提供了热点数据缓存功能,可以在这些产品上部署缓存解决方案,降低热点数据的缓存命中率。

2.对于热点数据,采用异步方式处理。对于访问较少的热点数据,可以采用异步的方式处理,将访问操作放入队列中,由后台线程去处理。而对于访问较多的热点数据,可以使用同步的方式处理,确保缓存命中率。

3.缓存数据的有效期。对热点数据设置较短的缓存有效期,使得缓存命中率降低,但不会影响缓存的整体性能。另外,对于一些实时性要求不高的业务,可以适当延长缓存有效期,以达到最优的效果。

分片缓存方案

随着互联网业务的发展,数据库也在增长。单一的数据库的存储能力已经无法满足需求。比如微信朋友圈的消息记录、手机通讯录、地图导航信息等。

为了解决这个问题,许多公司和组织开始采用分片方案,将数据划分为多个独立的数据库实例,每个实例负责管理其中一部分数据,彻底解决单库存储容量问题。然而,单个分片可能也会面临热点数据缓存的问题,甚至会成为系统性能瓶颈。

如何解决分片缓存问题?有以下几种方案:

1.数据分区。将数据按照某种规则分散到不同的分片中,每个分片的存储能力不同,从而缓解单个分片存储容量过小的问题。另外,可以基于数据特征对分片进行拆分,降低热点数据的影响。

2.异地多活架构。为了避免主备同步延迟带来的性能问题,可以将热点数据同步到多个可用区或区域,以提升系统的访问性能。

3.数据缓存分层。除了使用本地缓存,还可以通过多级缓存方案,将热点数据缓存在各级缓存中,提升系统的访问性能。第一级缓存可以部署在本地,第二级缓存部署在离用户最近的地方,第三级缓存部署在远处。第三级缓存需要依赖于云厂商的服务,比如亚马逊的CloudFront。

6.附录常见问题与解答

1.什么是MySQL查询缓存?

查询缓存是MySQL数据库系统提供的一种优化策略,能够对频繁执行的SELECT语句的结果进行缓存。通过缓存,下一次相同的SELECT语句的执行过程可直接从缓存中获取结果,避免重新计算,提高数据库查询效率。

2.为什么MySQL查询缓存能够提高查询效率?

查询缓存主要用于缓存查询语句的结果,避免重复计算,提高数据库查询效率。由于缓存命中率高,所以缓存占用内存很多,最终影响到了其他查询请求的响应时间。

3.MySQL查询缓存工作原理是什么样的?

MySQL查询缓存的工作原理是,当查询请求到来时,首先在缓存中查找该条SQL是否已经被缓存过,如果已经被缓存,则直接从缓存中返回查询结果;否则,才会真正去数据库中进行查询。缓存的存在可以极大的提高数据库查询效率。

4.查询缓存对什么类型的SQL语句生效?

查询缓存仅对SELECT类型的SQL语句有效。

5.查询缓存中SQL文本的匹配规则是什么?

查询缓存中SQL文本的匹配规则分两类:完全匹配和包含匹配。包含匹配就是将查询语句中的一些关键字包含在缓存的SQL文本中,且顺序相同。完全匹配就是查询语句与缓存的SQL文本完全相同。

6.MySQL查询缓存存在什么问题?

MySQL查询缓存存在以下问题:

1.缓存击穿:缓存击穿是指某个热点数据被访问的情况,当某个数据出现在缓存中时,由于某种原因(如缓存过期或缓存空间不足),导致无法及时的更新到缓存中,从而导致缓存中没有该数据,然后用户再次访问该数据时,由于此时缓存中并没有该数据,因此只能从源数据库中读取。这种现象称之为缓存击穿。

2.缓存穿透:缓存穿透(cache-penetration)是指在缓存和数据库中都没有对应的数据,导致用户查询不到想要的数据。缓存穿透是一种性能问题,当缓存和数据库中都没有相应的数据时,查询将会向源数据库发送请求,这种请求量可能会很大,甚至造成系统崩溃。

3.缓存雪崩:缓存雪崩(cache-avalanche)是指在某段时间内,缓存集体失效,所有请求都怼到数据库上。由于缓存过期时间短,刚好失效导致大量请求同时访问数据库,引起数据库压力过大,甚至宕机。

7.怎么设置MySQL查询缓存的过期时间?

可以使用查询语句:

SET QUERY_CACHE_TYPE = “ON”; //启用查询缓存
SET GLOBAL query_cache_type=“DEMAND”;//设置为"DEMAND"模式,仅对需要使用查询缓存的语句生效,缺省值也是"OFF"。
SET GLOBAL max_query_cache_size=; //设置缓存大小,缺省值为16M。
SET GLOBAL long_query_time=; //设置慢查询阈值,如果查询时间超过该值,则被视为慢查询,会打印到错误日志中。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/796198
推荐阅读
相关标签
  

闽ICP备14008679号