MySql一、查询和更新流程

知识体系
执行方法
MySQL 5.7 Reference Manual
阿里巴巴数据库技术

Mysql发展历史和版本分支:

工具基本使用

Navicat快捷键

1,Ctrl+q就会弹出一个sql输入窗口
2,Ctrl+r就执行sql了
3,按f6会弹出一个命令窗口
4,Ctrl+/ 注释
5,Ctrl +Shift+/ 解除注释
6,Ctrl+R 运行选中的SQL语句
7,Ctrl+Shift+R 只运行选中的sql语句
8,Ctrl+L 删除选中行内容
9,Ctrl+D 表的数据显示显示页面切换到表的结构设计页面,但是在查询页面写sql时是复制当前行并粘贴到下一行
10,Ctrl+N 打开一个新的查询窗口
11,Ctrl+W 关闭当前查询窗口
12,鼠标三击选择当前行

一、一条查询SQL语句是如何执行的?

日常开发中我们必不可少的会与数据库打交道,当我们的工具或者程序连接到数据库之后,实际发生了什么事情?它的内部又是怎么工作的呢?
以一条查询语句为例,来分析下MySQL的工作流程:

当我们的程序或者客户端要操作数据库时,第一步要做的就是与数据库建立连接。

1. 建立连接、通信协议

首先,MySQL 必须要运行一个服务,监听默认的 3306 端口。这个很好理解,因为我们从数据库取数据,一定要有对应的服务在提供数据。
MySQL是支持多种通信协议的,可以使用同步/异步的方式吗,支持长连接/短连接。

这里将通信协议拆开来看:第一个是通信类型,第二个是通信方式。

a. 通信类型

  • 通信类型
    同步 or 异步
同步通信的特点:
1、同步通信依赖于被调用方,受限于被调用方的性能。也就是说,应用操作数据库,线程会阻塞,等待数据库的返回。
2、一般只能做到一对一,很难做到一对多的通信。

异步通信:
1、异步可以避免应用阻塞等待,但是不能节省SQL执行的时间。
2、如果异步存在并发,每一个SQL的执行都要单独建立一个连接,避免数据混乱。但是这样会给服务端带来巨大的压力(一个连接就会创建一个线程,线程间切换回占用大量CPU资源)。另外异步通信还带来了编码的复杂度,所以一般不建议使用。如果要异步,必须使用连接池,排队从连接池中获取连接而不是创还能新的连接。

一般来说我们连接数据库都是同步连接。

  • 连接方式
    长连接 or 短连接
    MySQL即支持长连接,也支持短连接。短连接就是操作完毕以后,马上close掉。长连接可以保持打开,减少频繁创建、销毁带来的资源开销,后面的程序访问的时候还可以使用这个连接。一般我们会在连接池中使用长连接。

保持长连接会消耗内存,长时间不活动的连接,MySQL服务器会断开。

-- 查看mysql不同连接类型超时时间
	show global variables;
	show global variables like 'wait_timeout';   -- 非交互式超时时间,如JDBC程序
	show global variables like 'interactive_timeout';  -- 交互式超时时间,如数据库工具
	+---------------+-------+
	| Variable_name | Value |
	+---------------+-------+
	| wait_timeout  | 28800 |
	+---------------+-------+

默认都是 28800 秒,8 小时。

查看MySQL当前有多少个连接

show global status like 'Thread%';  -- 查看连接数
	+-------------------+-------+
	| Variable_name     | Value |
	+-------------------+-------+
	| Threads_cached    | 0     |
	| Threads_connected | 8     |
	| Threads_created   | 8     |
	| Threads_running   | 1     |
	+-------------------+-------+

Threads_cached: 缓存中的线程连接数;
Threads_connected: 当前打开的连接数;
Threads_created: 为处理连接创建的线程数;
Threads_running: 非睡眠状态的连接数,通常指并发连接数;
每产生一个连接或者一个会话,在服务端就会创建一个线程来处理。反过来,如果要杀死会话,就是Kill线程。

查看当前连接的状态

有了连接数,怎么知道当前连接的状态?

mysql> show processlist;  -- root用户,查看连接状态
+----+------+-----------------+-------------+---------+------+-------+------------------+
| Id | User | Host            | db          | Command | Time | State | Info             |
+----+------+-----------------+-------------+---------+------+-------+------------------+
|  1 | root | localhost:4699  | NULL        | Sleep   | 8555 |       | NULL             |
|  2 | root | localhost:4701  | learn       | Sleep   | 2924 |       | NULL             |
|  3 | root | localhost:4704  | learn       | Sleep   | 2695 |       | NULL             |
|  5 | root | localhost:13878 | lizhi       | Sleep   | 2918 |       | NULL             |
|  6 | root | localhost:13879 | auditpro3.0 | Sleep   | 2892 |       | NULL             |
|  7 | root | localhost:14560 | learn       | Query   |    0 | init  | show processlist |
|  8 | root | localhost:14624 | shen_mall   | Sleep   |  353 |       | NULL             |
|  9 | root | localhost:14625 | shen_mall   | Sleep   |  353 |       | NULL             |
+----+------+-----------------+-------------+---------+------+-------+------------------+

show-processlist
thread-status
一些常见的状态:

状态 含义
Sleep 线程正在等待客户端,以向它发送一个新语句
Query 线程正在执行查询或往客户端发送数据
Locked 该查询被其它查询锁定
Copying to tmp table on disk 临时结果集合大于 tmp_table_size。线程把临时表从存储器内部格式改变为磁盘模式,以节约存储器
Sendig data 线程正在为 SELECT 语句处理行,同时正在向客户端发送数据
Sorting for group 线程正在进行分类,以满足 GROUP BY 要求
Sorting for order 线程正在进行分类,以满足 ORDER BY 要求

MySQL最大连接数

在5.7版本默认是151个,最大可以设置程2^14(16384)。

mysql> show variables like 'max_connections';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 151   |
+-----------------+-------+
mysql show的参数说明
  1、级别: 全局global级别、会话session级别,不指明默认session;
  2、动态修改: set,重启后失效;永久生效,修改配置文件 /etc/my.cnf

查看配置的不同参数: show global/session variables like 'paramName111'; 
修改配置的不同参数(重启后会重置): set global/session paramName=value ;

e.g 
mysql> show global variables; -- 查看全局参数
mysql> set global max_connections=888;  -- 设置最大连接数

tips: mysql 不同参数配置

  • 通信协议
    MySQL支持哪些通信协议呢?
    Unix Socket:比如在Linux服务器上,如果不是使用'-h'参数登录,就是以socket方式登录的。它不用通过网络协议,也可以连接到MySQL的服务器,用到了服务器上的一个物理文件(/var/lib/mysql/mysql.sock)
    TCP/IP协议:使用'mysql -h182.168.xx.xx -uroot -p1234','-h'参数,就会用TCP/IP协议。编程语言的连接模块也都是用的TCP协议连接到MySQL服务器的,比如jdbc驱动包'mysql-connector-java-xx.jar'。

b. 通信方式

单工 : 数据单向传输,数据遥控器; 遥控器;
半双工 : 数据双向传输,但不能同时传输;对讲机;
全双工 : 数据双向传输,可以同时传输;打电话

mysql使用的是半双工方式。要么是客户端像服务器端发送数据,要么是服务器端向客户端发送数据,两个动作不能同时发生。所有客户端发送SQL给服务端的时候,一次连接里数据是不能分成小块发送的,不管你的SQL语句有多大,都是一次性发送。
比如平时批量插入数据,一次插入的数据量过大,如10万条,SQL很多,就会出现问题。

mysql> show variables like '%max_allowed%';
+--------------------------+------------+
| Variable_name            | Value      |
+--------------------------+------------+
| max_allowed_packet       | 4194304    |
| slave_max_allowed_packet | 1073741824 |
+--------------------------+------------+

此时可以将'max_allowed_packet'参数调大,默认为4194304bit,即4M。

执行一条查询语句,客户端跟服务端建立连接之后呢?下一步要做什么?

2. 查询缓存

MySQL内部自带了一个缓存模块,目的是为了加快读取速度。不过MySQL的查询缓存功能局限性很大,比如同一条SQL,中间多加一个空格就不能匹配缓存了;一张表的数据如果任何一条数据有变动,缓存也会失效;
所以MySQL自带的缓存模块是默认关闭的;常用的ORM框架其实已经提供了一级、二级缓存。
Query Cache

mysql> show variables like 'query_cache_type';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| query_cache_type | OFF   |
+------------------+-------+

默认我们没有使用缓存的话,就会跳过缓存的模块,下一步需要做什么呢?

3. 解析和预处理

  • a. 解析器_词法解析 : 把一个完整的SQL语句打碎成一个个单词。
    比如'select name from user_info where id = 1;',解析器会将它打碎成8个符号,
  • b. 解析器_语法解析 : 会对SQL做一些语法检查,比如单引号有没有闭合,然后根据MySQL定义的语法规则,根据SQL语句生成一个数据结构。这个数据结构我们称之为解析树(select_lex)。

    任何数据库的中间件,比如Mycat、Sharding-JDBC,都必须要有词法和语法分析功能。
  • c. 预处理器 :以上两种解析器可以分析词法和语法是否符合规范,但是当要确认有没有这张表、或者表里有没有对应字段时,还需要解析SQL环节的预处理器。
    预处理器会检查生成的解析树,解决解析器无法解析的语义。比如,会检查表和列名是否存在,检查名字和别名、保证没有歧义。
    预处理器之后会得到一个新的解析树。

4. 查询优化(Query Optimizer)与查询执行计划

a. 查询优化器

一条SQL语句是不是只有一种执行方式?或者数据库最终之星的SQL是不是就是我们发生的SQL?
答案显然是否定的,查看过执行计划的应该会清楚一条复杂SQL可以有多种执行方式,比如是走索引、全表扫描等。那么这么多种的执行方式是怎么得到的呢?最终会选择哪一种去执行?根据什么条件去选择的呢?
这就用到了MySQL的查询优化器模块。查询优化器的目的就是根据解析树生成不同的执行计划(Execution Plan),然后选择一种最优的执行计划(比如有多个索引可以使用,选择哪个索引?多表关联查询,以哪个表为基准?),MySQL里面使用的是基于开销(cost)的优化器,哪种执行计划开销最小,就用哪种。
结果:执行计划 Execution Plan Cost
优化器追踪:Optimizer_trace

mysql> show status like 'last_query_cost';  -- 查询最后一条执行语句的执行开销
+-----------------+-----------+
| Variable_name   | Value     |
+-----------------+-----------+
| Last_query_cost | 10.499000 |
+-----------------+-----------+

b. 优化器怎么得到执行计划的

https://dev.mysql.com/doc/internals/en/optimizer-tracing.html
首先查看优化器状态,并在需要时临时开启。使用完毕后记得关闭它,因为开关打开后会把优化分析的结果写在表里面,消耗性能。

mysql> show variables like 'optimizer_trace%';  -- 查看优化器状态
+------------------------------+----------------------------------------------------------------------------+
| Variable_name                | Value                                                                      |
+------------------------------+----------------------------------------------------------------------------+
| optimizer_trace              | enabled=off,one_line=off                                                   |
| optimizer_trace_features     | greedy_search=on,range_optimizer=on,dynamic_range=on,repeated_subselect=on |
| optimizer_trace_limit        | 1                                                                          |
| optimizer_trace_max_mem_size | 16384                                                                      |
| optimizer_trace_offset       | -1                                                                         |
+------------------------------+----------------------------------------------------------------------------+
    1. 临时打开优化器开关
mysql> set optimizer_trace='enabled=on';  -- 临时开启
Query OK, 0 rows affected
    1. 执行一条SQL,此时优化器会将执行计划存入表中
SELECT * FROM tb_order A left join tb_order_item B ON A.order_id = B.order_id
    1. 去系统表中查看优化器分析的过程。
SELECT * FROM information_schema.optimizer_trace;

查询得到的是一个JSON类型的数据,主要分为:准备阶段_'join_preparation',优化阶段_'join_optimization'和执行阶段_'join_execution' 三阶段。

mysql> SELECT * FROM information_schema.optimizer_trace;
+-------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+-------------------------+
| QUERY                                                                         | TRACE                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | MISSING_BYTES_BEYOND_MAX_MEM_SIZE | INSUFFICIENT_PRIVILEGES |
+-------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+-------------------------+
| SELECT * FROM tb_order A left join tb_order_item B ON A.order_id = B.order_id | {
  "steps": [
    {
      "join_preparation": {
        "select#": 1,
        "steps": [
          {
            "expanded_query": "/* select#1 */ select `a`.`order_id` AS `order_id`,`a`.`payment` AS `payment`,`a`.`payment_type` AS `payment_type`,`a`.`status` AS `status`,`a`.`create_time` AS `create_time`,`a`.`update_time` AS `update_time`,`a`.`payment_time` AS `payment_time`,`a`.`consign_time` AS `consign_time`,`a`.`end_time` AS `end_time`,`a`.`close_time` AS `close_time`,`a`.`user_id` AS `user_id`,`a`.`unique_key` AS `unique_key`,`b`.`id` AS `id`,`b`.`item_id` AS `item_id`,`b`.`order_id` AS `order_id`,`b`.`num` AS `num`,`b`.`title` AS `title`,`b`.`price` AS `price`,`b`.`total_fee` AS `total_fee`,`b`.`pic_path` AS `pic_path`,`b`.`status` AS `status`,`b`.`create_time` AS `create_time`,`b`.`update_time` AS `update_time` from (`tb_order` `a` left join `tb_order_item` `b` on((`a`.`order_id` = `b`.`order_id`)))"
          }
        ]
      }
    },
    {
      "join_optimization": {
        "select#": 1,
        "steps": [
          {
            "transformations_to_nested_joins": {
              "transformations": [
                "parenthesis_removal"
              ],
              "expanded_query": "/* select#1 */ select `a`.`order_id` AS `order_id`,`a`.`payment` AS `payment`,`a`.`payment_type` AS `payment_type`,`a`.`status` AS `status`,`a`.`create_time` AS `create_time`,`a`.`update_time` AS `update_time`,`a`.`payment_time` AS `payment_time`,`a`.`consign_time` AS `consign_time`,`a`.`end_time` AS `end_time`,`a`.`close_time` AS `close_time`,`a`.`user_id` AS `user_id`,`a`.`unique_key` AS `unique_key`,`b`.`id` AS `id`,`b`.`item_id` AS `item_id`,`b`.`order_id` AS `order_id`,`b`.`num` AS `num`,`b`.`title` AS `title`,`b`.`price` AS `price`,`b`.`total_fee` AS `total_fee`,`b`.`pic_path` AS `pic_path`,`b`.`status` AS `status`,`b`.`create_time` AS `create_time`,`b`.`update_time` AS `update_time` from `tb_order` `a` left join `tb_order_item` `b` on((`a`.`order_id` = `b`.`order_id`))"
            }
          },
          {
            "table_dependencies": [
              {
                "table": "`tb_order` `a`",
                "row_may_be_null": false,
                "map_bit": 0,
                "depends_on_map_bits": [
                ]
              },
              {
                "table": "`tb_order_item` `b`",
                "row_may_be_null": true,
                "map_bit": 1,
                "depends_on_map_bits": [
                  0
                ]
              }
            ]
          },
          {
            "ref_optimizer_key_uses": [
              {
                "table": "`tb_order_item` `b`",
                "field": "order_id",
                "equals": "`a`.`order_id`",
                "null_rejecting": false
              },
              {
                "table": "`tb_order_item` `b`",
                "field": "order_id",
                "equals": "`a`.`order_id`",
                "null_rejecting": false
              }
            ]
          },
          {
            "rows_estimation": [
              {
                "table": "`tb_order` `a`",
                "table_scan": {
                  "rows": 31,
                  "cost": 1
                }
              },
              {
                "table": "`tb_order_item` `b`",
                "table_scan": {
                  "rows": 55,
                  "cost": 4
                }
              }
            ]
          },
          {
            "considered_execution_plans": [
              {
                "plan_prefix": [
                ],
                "table": "`tb_order` `a`",
                "best_access_path": {
                  "considered_access_paths": [
                    {
                      "access_type": "scan",
                      "rows": 31,
                      "cost": 7.2,
                      "chosen": true
                    }
                  ]
                },
                "cost_for_plan": 7.2,
                "rows_for_plan": 31,
                "rest_of_plan": [
                  {
                    "plan_prefix": [
                      "`tb_order` `a`"
                    ],
                    "table": "`tb_order_item` `b`",
                    "best_access_path": {
                      "considered_access_paths": [
                        {
                          "access_type": "ref",
                          "index": "oder_item_id",
                          "rows": 1,
                          "cost": 31.2,
                          "chosen": true
                        },
                        {
                          "access_type": "ref",
                          "index": "order_id",
                          "rows": 1,
                          "cost": 31.2,
                          "chosen": false
                        },
                        {
                          "access_type": "scan",
                          "using_join_cache": true,
                          "rows": 42,
                          "cost": 267.17,
                          "chosen": false
                        }
                      ]
                    },
                    "cost_for_plan": 44.4,
                    "rows_for_plan": 31,
                    "chosen": true
                  }
                ]
              }
            ]
          },
          {
            "condition_on_constant_tables": "1",
            "condition_value": true
          },
          {
            "attaching_conditions_to_tables": {
              "original_condition": "1",
              "attached_conditions_computation": [
              ],
              "attached_conditions_summary": [
                {
                  "table": "`tb_order` `a`",
                  "attached": null
                },
                {
                  "table": "`tb_order_item` `b`",
                  "attached": null
                }
              ]
            }
          },
          {
            "refine_plan": [
              {
                "table": "`tb_order` `a`",
                "access_type": "table_scan"
              },
              {
                "table": "`tb_order_item` `b`"
              }
            ]
          }
        ]
      }
    },
    {
      "join_execution": {
        "select#": 1,
        "steps": [
        ]
      }
    }
  ]
} |                                 0 |                       0 |
+-------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+-------------------------+
1 row in set

可以细致的卡下JSON中的具体字段。

expanded_query : 代表优化后的SQL语句。
considered_execution_plans : 里面列出了所有的执行计划。

    1. 分析完记得关掉。
      'set optimizer_trace='enabled=off';'
mysql> show variables like 'optimizer_trace';
+-----------------+-------------------------+
| Variable_name   | Value                   |
+-----------------+-------------------------+
| optimizer_trace | enabled=on,one_line=off |
+-----------------+-------------------------+

mysql> set optimizer_trace='enabled=off';
Query OK, 0 rows affected

mysql> show variables like 'optimizer_trace';
+-----------------+--------------------------+
| Variable_name   | Value                    |
+-----------------+--------------------------+
| optimizer_trace | enabled=off,one_line=off |
+-----------------+--------------------------+

优化器最终会把解析树变成一个查询查询执行计划,查询执行计划是一个树结构。
这个执行计划也不一定是最优的执行计划,比较MySQL也有可能覆盖不到所有的执行计划。

除了临时打开执行优化器的开关来查看执行计划外,我们在SQL语句前加上'EXPLAIN',也可以查看到执行计划的信息。

mysql> EXPLAIN SELECT * FROM tb_order A left join tb_order_item B ON A.order_id = B.order_id;
+----+-------------+-------+------+-----------------------+--------------+---------+----------------------+------+-------+
| id | select_type | table | type | possible_keys         | key          | key_len | ref                  | rows | Extra |
+----+-------------+-------+------+-----------------------+--------------+---------+----------------------+------+-------+
|  1 | SIMPLE      | A     | ALL  | NULL                  | NULL         | NULL    | NULL                 |   31 | NULL  |
|  1 | SIMPLE      | B     | ref  | oder_item_id,order_id | oder_item_id | 152     | shen_mall.A.order_id |    1 | NULL  |
+----+-------------+-------+------+-----------------------+--------------+---------+----------------------+------+-------+

5. 存储引擎

得到执行计划以后,SQL语句是不是终于可以执行了?
此时就要考虑到:我们要查询的数据是放在哪里的?执行计划在哪里执行?

a. 存储引擎介绍

首先我们的数据是存储在表里面的,表在存储数据时,还会组织数据的存储结构,这个存储结构就是由我们的存储引擎决定的。
在MySQL里,支持多种存储引擎,他们是可以替换的。

b. 查看存储引擎

  • 每张表使用的存储引擎可以通过DDL建表语句来查看。
  • 也可以通过命令 'show table status from your_db_name;'来查看数据库中每张表的存储引擎
mysql> show table status from shen_mall;
+---------------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+---------------------+------------+-----------------+----------+----------------+----------+
| Name          | Engine | Version | Row_format | Rows | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Create_time         | Update_time         | Check_time | Collation       | Checksum | Create_options | Comment  |
+---------------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+---------------------+------------+-----------------+----------+----------------+----------+
| tb_item       | InnoDB |      10 | Compact    |   23 |            712 |       16384 |               0 |        49152 |         0 | NULL           | 2020-08-15 17:29:37 | NULL                | NULL       | utf8_general_ci | NULL     |                | 商品表   |
| tb_item_cat   | InnoDB |      10 | Compact    |   26 |            630 |       16384 |               0 |        32768 |         0 |            299 | 2020-08-15 17:29:38 | NULL                | NULL       | utf8_general_ci | NULL     |                | 商品类目 |
| tb_item_demo  | MyISAM |      10 | Dynamic    |    0 |              0 |           0 | 281474976710655 |         1024 |         0 |            299 | 2020-08-31 20:39:23 | 2020-08-31 20:39:23 | NULL       | utf8_general_ci | NULL     |                | 商品类目Demo |
| tb_order      | InnoDB |      10 | Compact    |   31 |            528 |       16384 |               0 |        49152 |         0 | NULL           | 2020-08-15 17:29:40 | NULL                | NULL       | utf8_bin        | NULL     |              

在MySQL中,为单独每张表都可以指定它的存储引擎,而不是一个数据库只能使用一个存储引擎。

我们刚才提到一张表所使用的的存储引擎决定了存储数据的结果,那么具体是怎么存储的呢?
首先,找到数据库存放数据的路径'show variables like 'datadir';'
之后,在该目录下找到对应数据库目录,在该目录下可以看到‘表名.frm’的文件。任何一个存储引擎都会有一个frm文件,这个是表结构定义的文件。

不同的存储引擎存放数据的方式不一样,产生的文件也不一样,innodb引擎是1个,memory没有,myisam引擎是两个。
那么这些存储引擎的差别在哪里呢?

c.存储引擎比较

常见存储引擎
MyISAM和InnoDB是我们用的最多的俩个存储引擎,在MySQL5.5版本之前,默认的存储引擎是MyISAM,它是MySQL自带的,当我们在此版本之前创建表时不指定存储引擎的话,默认就是使用的MyISAM引擎。
5.5版本之后,默认的存储引擎改成了InnoDB,它是第三方公司为MySQL开发的。和MyISAM相比,InnoDB支持事务、支持行级别的锁,对于业务一致性要求高的场景来说更为合适。
数据库支持的存储引擎
可以使用'show engines;'命令来查看所有的存储引擎。

mysql> show engines;
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| Engine             | Support | Comment                                                        | Transactions | XA   | Savepoints |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| FEDERATED          | NO      | Federated MySQL storage engine                                 | NULL         | NULL | NULL       |
| MRG_MYISAM         | YES     | Collection of identical MyISAM tables                          | NO           | NO   | NO         |
| MyISAM             | YES     | MyISAM storage engine                                          | NO           | NO   | NO         |
| BLACKHOLE          | YES     | /dev/null storage engine (anything you write to it disappears) | NO           | NO   | NO         |
| CSV                | YES     | CSV storage engine                                             | NO           | NO   | NO         |
| MEMORY             | YES     | Hash based, stored in memory, useful for temporary tables      | NO           | NO   | NO         |
| ARCHIVE            | YES     | Archive storage engine                                         | NO           | NO   | NO         |
| InnoDB             | DEFAULT | Supports transactions, row-level locking, and foreign keys     | YES          | YES  | YES        |
| PERFORMANCE_SCHEMA | YES     | Performance Schema                                             | NO           | NO   | NO         |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
9 rows in set

可以看到,这些引擎的描述、对事务的支持与否、是否支持XA协议(用来实现分布式事务)、Savepoints(用来实现子事务、嵌套事务)。
https://dev.mysql.com/doc/refman/5.7/en/storage-engines.html 官方文档也会有对每种存储引擎的介绍。

MyISAM:

MyISAM: These tables have a small footprint. Table-level locking limits the performance in read/write workloads, so it is often used in read-only or read-mostly workloads in Web and data warehousing configurations.

应用范围比较小。表级锁限制了读写的性能,所以常常被用来做只读或者读多写少的工作。

  • 特点:
    支持表级别的锁(插入、更新都会锁表),不支持事务;
    拥有较高的插入(insert)和查询(select)速度;
    存储了表的行数(count的速度更快)。
  • 应用场景:
    只读一类的数据分析的项目;
    向数据库批量插入数百万数据,可以先将表设置为MyISAM引擎类型来插入数据,然后修改存储引擎为InnoDB。

InnoDB

InnoDB: The default storage engine in MySQL 5.7. InnoDB is a transaction-safe (ACID compliant) storage engine for MySQL that has commit, rollback, and crash-recovery capabilities to protect user data. InnoDB row-level locking (without escalation to coarser granularity locks) and Oracle-style consistent nonlocking reads increase multi-user concurrency and performance. InnoDB stores user data in clustered indexes to reduce I/O for common queries based on primary keys. To maintain data integrity, InnoDB also supports FOREIGN KEY referential-integrity constraints. For more information about InnoDB, see Chapter 14, The InnoDB Storage Engine.... https://dev.mysql.com/doc/refman/5.7/en/innodb-storage-engine.html

MySQL5.7默认的存储引擎。是一个事务安全的MySQL存储引擎,支持事务的提交、回滚、崩溃恢复来保护用户数据。InnoDB的行级锁和Oracle的一致非锁读提高了多用户并发性和性能。InnoDB将数据存储在聚集索引中,以减少基于主键的常见查询的I/O。为了保持数据的完整性,InnoDB还支持外检引用完整性约束。

  • 特点:
    支持事务、外键,因此数据的完整性、一致性更高;
    支持行级别和表级别的锁;
    支持读写并发、并不阻塞读;
    特殊的索引存放方式、可以减少IO、提升查询效率;
  • 应用场景:
    读写都频繁的表,存在并发读写或者有事务需求的业务系统。

Memory

Memory: Stores all data in RAM, for fast access in environments that require quick lookups of non-critical data. This engine was formerly known as the HEAP engine. Its use cases are decreasing; InnoDB with its buffer pool memory area provides a general-purpose and durable way to keep most or all data in memory, and NDBCLUSTER provides fast key-value lookups for huge distributed data sets.

将所有数据存储在RAM中,以便在需要快速查找非关键数据的环境中快速访问。这个引擎以前被称为堆引擎。其使用案例正在减少;InoDB 及其缓冲池内存区域提供了一种通用、持久的方法来将大部分或所有数据保存在内存中,而 ndbcluster 为大型分布式数据集提供了快速的键值查找

  • 特点:
    数据存储在内存中,读写速度很快,但是当数据库重启或崩溃,数据会全部消失。
  • 应用场景:
    只适合做临时表。

CSV

CSV: Its tables are really text files with comma-separated values. CSV tables let you import or dump data in CSV format, to exchange data with scripts and applications that read and write that same format. Because CSV tables are not indexed, you typically keep the data in InnoDB tables during normal operation, and only use CSV tables during the import or export stage.

它的表实际上是带有逗号分隔值的文本文件。csv表允许以csv格式导入或转储数据,以便与读写相同格式的脚本和应用程序交换数据。因为 csv 表没有索引,所以通常在正常操作期间将数据保存在 inodb 表中,并且只在导入或导出阶段使用 csv 表。

  • 特点:
    不允许空行,不支持索引;
    格式通用,可以直接编辑;
  • 应用场景
    因为格式通用,可以直接编辑,适合在不同数据库之间导入导出。

Archive

Archive: These compact, unindexed tables are intended for storing and retrieving large amounts of seldom-referenced historical, archived, or security audit information.

这些紧凑的未索引的表用于存储和检索大量很少引用的历史、存档或安全审计信息。

  • 特点:
    不支持索引,不支持 update delte。

这是 MySQL 里面常见的一些存储引擎,我们看到了,不同的存储引擎提供的特性都不一样,它们有不同的存储机制、索引方式、锁定水平等功能。
我们在不同的业务场景中对数据操作的要求不同,就可以选择不同的存储引擎来满足我们的需求,这个就是 MySQL 支持这么多存储引擎的原因

d. 选择合适的存储引擎

如果对数据一致性要求较高,需要支持事务,可以选择InnoDB;
如果数据读多写少,对查询性能要求较高,可以选择MyISAM;
如果需要一个用于查询的临时表,可以选择Memory;
如果目前的存储引擎都不能满足你的需求,可以根据官网手册使用C语言自定义一个存储引擎:https://dev.mysql.com/doc/internals/en/custom-engine.html

到这里,我们请求了存储数据的形式。那么是谁使用执行计划去操作存储引擎呢?

6. 执行引擎(Query Execution Engine),返回结果

执行引擎负责使用执行计划去操作存储引擎,它利用存储引擎提供的相应API来完成操作。
当我们修改了表的存储引擎,对数据的CRUD操作不需要做任何改变,这是因为不同功能的存储引擎实现了相同的API,对外接口时一致的。
执行引擎最后把数据返回给客户端,即使没有结果也要返回。

二、MySq体系结构

基于上面一条查询SQL的执行流程,下面梳理一下MySQL的内部模块。

1. 模块详解

    1. Connector:建立连接,用来支持各种语言和SQL的交互,比如Ruby、Python、PHP、Java的JDBC等;
    1. Management Services & Utilities : 系统管理和控制工具,包括备份恢复、复制、集群等;
    1. Connection Pool : 连接池,管理需要缓存的资源,包括用户、密码、权限、线程等;
    1. SQL Interface : 用来接收用户的SQL命令,返回用户需要的查询结果;
    1. Parser : 解析器,用来解析SQL语句;词法解析、语法解析及预处理;
    1. Optimizer : 查询优化器,根据开销生成执行计划;
    1. Caches & Buffers : 查询缓存,除了行记录的缓存之外,还有表缓存、Key缓存、权限缓存等;
    1. Pluhhable Storage Engines : 插件式存储引擎(InnoDB、MyISAM、Memory),它提供API给服务层使用,跟具体的文件打交道;

2. 架构分层

总体上,可以将MySQL分成三层,和客户端对接的连接层,真正执行操作的服务层,和硬件打交道的存储引擎层。

a.连接层

我们的客户端要连接到 MySQL 服务器 306 端口,必须要跟服务端建立连接,那么管管理所有的连接,验证客户端的身份和权限,这些功能就在连接层完成。

b. 服务层

解析器 -> 预处理 -> 执行优化器 -> 执行器
连接层会把 SQL 语句交给服务层,这里面又包含一系列的流程:
比如查询缓存的判断、根据 SQL 调用相应的接口,对我们的 SQL 语句进行词法和语法的解析(比如关键字怎么识别,别名怎么识别,语法有没有错误等)。
然后就是优化器,MySQL 底层会根据一定的规则对我们的 SQL 语句进行优化,最后再交给执行器去执行。

c.存储引擎

存储引擎就是我们的数据真正存放的地方,在 MySQL 里面支持不同的存储引擎。
再往下就是内存或者磁盘。

三、一条更新SQL是如何执行的?

前面描述了查询SQL的执行流程,接下来介绍一下更新SQL的执行流程,在数据库内认为删除、修改、插入都是更新操作,都归为更新流程。
更新流程和之前的查询流程有什么不同呢?
首先,基本流程是一致的,都会经过 建立连接、查缓存、词法解析/语法解析/预处理、查询优化器、执行引擎、存储引擎。区别就在于拿到符合条件的数据之后的操作。
不过为了提升交互性能,每次会先从内存中读取数据,如果内存中已存在则直接读取,不存在的话就从磁盘中读取同时加入内存;修改时先修改内存中数据,然后后台线程异步将数据同步至磁盘。

1. 缓冲池 Buffer Pool

首先,InnoDB的数据都是放在磁盘上的,InnoDB操作数据有一个最小的逻辑单位,叫做页(索引页和数据页)。我们对于数据的操作,不是每次都直接操作磁盘,因为磁盘的速度太慢了、InnoDB使用了一种缓冲池的技术。也就是把磁盘读到的页放到一块内存区域里面。这个内存区域就叫做Buffer Pool。

下一次读取相同的也,先判断是不是在缓冲池里面,如果是,就直接读取,不用再次访问磁盘。
修改数据的时候,先修改缓冲池里面的页。内存的数据页和磁盘数据不一致的时候,我们把它叫做脏页。InnoDB内部有专门的后台线程把Buffer Pool的数据写入到磁盘,每隔一段时间就一次性地把多个修改写入磁盘,这个动作称之为刷脏
Buffer Pool是InnoDB里面非常重要的一个结构,它的内部又分成几块区域。这里我们趁机到官网来认识一下InnoDB的内存结构和磁盘结构。

2. InnoDB内存结构和磁盘结构

https://dev.mysql.com/doc/refman/8.0/en/innodb-architecture.html

2.1 内存结构

Buffer Pool主要分为3个部分:Buffer Pool、Change Buffer、Adaptive Hash Index,另外还有一个(redo) log buffer。

a. Buffer Pool

Buffer Pool缓存的是页面信息,包括数据也、索引页。
查看服务器状态,里面有很多跟Buffer Pool相关的信息:

mysql> show status like '%innodb_buffer_pool%';
+---------------------------------------+-------------+
| Variable_name                         | Value       |
+---------------------------------------+-------------+
| Innodb_buffer_pool_dump_status        | not started |
| Innodb_buffer_pool_load_status        | not started |
| Innodb_buffer_pool_pages_data         | 456         |
| Innodb_buffer_pool_bytes_data         | 7471104     |
| Innodb_buffer_pool_pages_dirty        | 0           |
| Innodb_buffer_pool_bytes_dirty        | 0           |
| Innodb_buffer_pool_pages_flushed      | 1           |
| Innodb_buffer_pool_pages_free         | 7734        |
| Innodb_buffer_pool_pages_misc         | 2           |
| Innodb_buffer_pool_pages_total        | 8192        |
| Innodb_buffer_pool_read_ahead_rnd     | 0           |
| Innodb_buffer_pool_read_ahead         | 0           |
| Innodb_buffer_pool_read_ahead_evicted | 0           |
| Innodb_buffer_pool_read_requests      | 12490       |
| Innodb_buffer_pool_reads              | 457         |
| Innodb_buffer_pool_wait_free          | 0           |
| Innodb_buffer_pool_write_requests     | 1           |
+---------------------------------------+-------------+

参数具体含义可以在官网查看:https://dev.mysql.com/doc/refman/8.0/en/server-status-variables.html

mysql> show variables like '%innodb_buffer_pool%';
+-------------------------------------+----------------+
| Variable_name                       | Value          |
+-------------------------------------+----------------+
| innodb_buffer_pool_dump_at_shutdown | OFF            |
| innodb_buffer_pool_dump_now         | OFF            |
| innodb_buffer_pool_filename         | ib_buffer_pool |
| innodb_buffer_pool_instances        | 8              |
| innodb_buffer_pool_load_abort       | OFF            |
| innodb_buffer_pool_load_at_startup  | OFF            |
| innodb_buffer_pool_load_now         | OFF            |
| innodb_buffer_pool_size             | 134217728      |
+-------------------------------------+----------------+

参数具体含义可以在官网查看: https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html
Buffer Pool默认大小是'innodb_buffer_pool_size'参数控制的,默认134217728字节,即128M;
内存的缓冲池写满了会怎么办?(Redis设置的内存满了是怎么处理的)InnoDB采用了LRU(Least recently used,最近最少使用)算法来管理缓冲池。
内存缓冲区对于提升读写性能有很大的作用。思考一个问题:
当需要更新一个数据页时,如果数据页在 Bufer Pol 中存在,那么就直接更新好了。否则的话就需要从磁盘加载到内存,再对内存的数据页进行操作。也就是说,如果没有命中缓冲池,至少要产生一次磁盘 IO,有没有优化的方式呢?

b. Change Buffer 写缓冲

如果这个数据页的数据不需要进行唯一性校验等,此时也就不需要从磁盘加载索引页判断数据是不是重复(唯一性检查)。这种情况下可以先把修改操作记录在内存的缓冲池中,从而提升更新语句(Insert、Update、Delete)的执行速度。
这一块区域就是Change Buffer。5.5版本之前叫Insert Buffer插入缓冲,现在也能支持delte和update。
最后把Change Buffer记录到数据页的操作叫做merge。什么时候发生merge?有以下几种情况:在访问这个数据页的时候、通过后台线程/数据库shut down、redo log写满时触发。
如果数据库大部分索引都是非唯一索引,并且业务是写多读少,不会再写数据后立刻读取,就可以使用Chnage Buffer(写缓冲)。写多读少的业务,可以调大Change Buffer内存:

mysql> show variables like 'innodb_change_buffer%';
+-------------------------------+-------+
| Variable_name                 | Value |
+-------------------------------+-------+
| innodb_change_buffer_max_size | 25    |
| innodb_change_buffering       | all   |
+-------------------------------+-------+

'innodb_change_buffer_max_size'代表Change Buffer占Buffer Pool的比例,默认25%;

c. Adaptive Hash Index

d. (redo) log buffer

思考一个问题:如果Buffer Pool里面的脏页还没有刷入磁盘时,数据库宕机或者重启,内存中还未持久化的数据就会丢失。如果写操作写到一半,甚至可能会破坏数据文件导致数据库不可用。
为了避免这个问题,InnoDB把所有对页面的修改操作专门写入一个日志文件,并且在数据库启动时从这个文件进行恢复操作(实现crash-safe)-以此来实现事务的持久化。

这个文件就是磁盘的redo log(叫做重做日志),对应于/var/lib/mysql/目录下的ib_logfile0和ib_logfile1,每个48M。

这种日志和磁盘配合的整个过程,其实就是MySQL里的WAL技术(Write-Ahead Logging),它的关键点就是先写日志,再写磁盘。

mysql> show variables like 'innodb_log%';
+-----------------------------+----------+
| Variable_name               | Value    |
+-----------------------------+----------+
| innodb_log_buffer_size      | 8388608  |
| innodb_log_compressed_pages | ON       |
| innodb_log_file_size        | 50331648 |   -- 指定每个文件的大小,默认48N
| innodb_log_files_in_group   | 2        |   -- 指定文件的数量,默认为2
| innodb_log_group_home_dir   | .\       |   -- 指定文件所在路径,相对or绝对路径。不指定的话为datadir路径。
+-----------------------------+----------+

此处记录日志虽然也是磁盘操作,但是与直接读取磁盘相比,直接读取磁盘时如果数据分散在不同扇区,则会进行刷盘查找读取,刷盘是随机I/O;而记录日志时数据是连续存放的,是顺序I/O;因此先把修改写入日志,可以延迟刷盘时机,进而提升系统吞吐。

当然redo log也不是每一次都直接写入磁盘,在Buffer Pool里面有一块内存区域(Log Buffer)专门用来保存即将要写入日志文件的数据,默认16M,它一样可以节省磁盘I/O。

mysql> show variables like 'innodb_log_buffer_size';
+------------------------+---------+
| Variable_name          | Value   |
+------------------------+---------+
| innodb_log_buffer_size | 8388608 |
+------------------------+---------+

需要注意:redo log 的内容主要是用于崩溃恢复。磁盘的数据文件,数据来自 bufer pool。redo log 写入磁盘,不是写入数据文件。
那么,Log Buffer 什么时候写入 log file?
在我们写入数据到磁盘的时候,操作系统本身是有缓存的。flush 就是把操作系统缓冲区写入到磁盘。
log buffer写入磁盘的实际,由一个参数控制,默认是1:

mysql> show variables like 'innodb_flush_log_at_trx_commit';
+--------------------------------+-------+
| Variable_name                  | Value |
+--------------------------------+-------+
| innodb_flush_log_at_trx_commit | 1     |
+--------------------------------+-------+
含义
0(延迟写) log buffer 将每秒一次地写入 log file 中,并且与 log file 的 flush 操作同时进行。该模式下,在事务提交的时候,不会主动触发写入磁盘的操作。
1(默认,实时写,实时刷) 每次事务提交时 MySQL 都会把 log buffer 的数据写入 log file,并且刷到磁盘中去。
2(实时写,延迟刷) 每次事务提交时 MySQL 都会把 log bufer 的数据写入 log file。但是 flush 操作并不会同时进行。该模式下,MySQL 会每秒执行一次 flush 操作。
redo log作为InnoDB存储引擎的实现,用于备份恢复内存中的数据至磁盘,有以下几个特点: 1. redo log是InnoDB存储引擎实现的,并不是所有存储引擎都有; 2. 不是记录数据页更新之后的状态,而是记录这个页做了什么改动,属于屋里日志; 3. redo log的大小是固定的,前面的内容会被覆盖; check point是当前要覆盖的位置。如果write pos跟check point重叠,说明redo log已经写满,这时需要同步redo log到磁盘中。

至此,MySQL内存区域介绍完毕:Buffer Pool、change buffer、Adaptive Hash Index、log buffer。

数据存储在磁盘中,磁盘结构里面主要是各种各样的表空间,叫做Table space。

2.2 磁盘结构

表空间可以看做是InnoDB存储引擎逻辑结构的最高层,所有的数据都存放在表空间中,InnoDB的表空间分为5大类。

a.系统表空间 system tablespace

在默认情况下InnoDB存储引擎有一个共享表空间(对应文件/var/lib/mysql/),也叫作系统表空间。
InnoDB系统表空间包含InnoDB数据字典和双写缓冲区,Change Buffer和Undo Logs,如果没有指定file-per-table,也包含用户创建的表和索引数据。
InnoDB的页和操作系统的页大小不一致,InnoDB页大小一般为16K,操作系统页大小为4K,InnoDB的页写入到磁盘时,一个页需要分4次写。

存储存储引擎在将16K的页的数据写入到磁盘时发生了宕机,可能只写入了16K的一部分,比如4k,这时就出现了部分写失效(partial page write),可能会导致数据丢失。

mysql> show variables like 'innodb_doublewrite';
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| innodb_doublewrite | ON    |
+--------------------+-------+

虽然之前介绍了有redo log来备份恢复数据,但如果这个页本身已经损坏,用它来做崩溃恢复是没有意义的。所以在对于应用 redo log 之前,需要一个页的副本。如果出现了写入失效,就用页的副本来还原这个页,然后再应用 redo log。这个页的副本就是 double write,InnoDB 的双写技术。通过它实现了数据页的可靠性。
和redo log一样,double write由两部分组成,一部分是内存的 double write,一部分是磁盘上的double write。因为double write是顺序写入的,不会带来很大的开销。
在默认情况下,所有的表共享一个系统表空间,这个文件会越来越大,而且它的空间不回收缩。

b.独占表空间 file-per-table tablespaces

我们可以为每张表独占一个表空间。这个开关通过innodb_file_per_table设置,默认开启。

mysql> show variables like 'innodb_file_per_table';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_file_per_table | ON    |
+-----------------------+-------+

开启后,每张表都会开辟一个表空间,这个文件就是数据目录下的idb文件(例如 /var/lib/mysql/gupao/tb_order.ibd),存放表的索引和数据。
但是其他类的数据,如回滚(undo)信息,插入缓冲索引页、系统事务信息,二次写缓冲(Double write bufer)等还是存放在原来的共享表空间内。

c.通用表空间 general tablespaces

通用表空间也是一种共享的表空间,和ibdata1类似。
可以创建一个通用的表空间,用来存储不同数据库的表,数据路径和文件可以自定义。

create tablespace ts2673 add datafile '/var/lib/mysql/ts2673.ibd' file_block_size=16K engine=innodb;

在创建表的时候可以指定表空间,用ALTER修改表空间可以转移表空间:

create table t0901(id integer) tablespace ts0901;

不同表空间的数据是可以移动的。
删除表空间需要先删除里面的所有表:

drop table t0901;
drop tablespace ts0901;

d.临时表空间 temporary tablespaces

存储临时表的数据,包括用户创建的临时表,和磁盘的内部临时表。对应数据目录下的ibtmp1文件。当数据服务器正常关闭时,该表空间会被删除,下次重新生成。

e.undo log tablespaces

undo log(撤销日志或回滚日志)记录了事务发生之前的数据状态(不包括 select)。如果修改数据时出现异常,可以用 undo log 来实现回滚操作(保持原子性)。
在执行 undo 的时候,仅是将数据从逻辑上恢复至事务之前的状态,而不是从物理页面上操作实现的,属于逻辑格式的日志。
redo Log 和 undo Log 与事务密切相关,统称为事务日志。
undo Log 的数据默认在系统表空间 ibdata1 文件中,因为共享表空间不会自动收缩,也可以单独创建一个 undo 表空间。

mysql> show variables like '%undo%';
+-------------------------+-------+
| Variable_name           | Value |
+-------------------------+-------+
| innodb_undo_directory   | .     |
| innodb_undo_logs        | 128   |
| innodb_undo_tablespaces | 0     |
+-------------------------+-------+

有了这些日志之后,可以总结一下一个更新操作的流程,这是一个简化的过程 :
name原值是zhangsan;
'update user set name = 'lisi' wher id=1;'
1、事务开始,从内存或磁盘读取到这条数据,返回给Server的执行器;
2、执行器修改这一行数据的值为lisi;
3、记录name=lisi到undo log;
4、记录name=lisi到redo log;
5、调用存储引擎接口,在内存(Buffer Pool)中修改name=lisi;
6、事务提交。

Redo log

磁盘中还有一块区域是 Redo log,备份恢复数据。

内存、磁盘之间需要异步进行交互,所以后台工作着很多线程。

2.3 后台线程

后台线程的主要作用是负责刷新内存池中的数据和把修改的数据页刷新到磁盘。后台线程分为:master thread,IO thread,purge thread,page cleaner thread。
master thread :负责刷新缓存数据到磁盘并协调度其它后台进程。
IO thread 分为 insert bufer、log、read、write 线程。分别用来处理 insert bufer、重做日志、读写请求的 IO 回调。
purge thread 用来回收 undo 页。
page cleaner thread 用来刷新脏页。

除了 InoDB 架构中的日志文件,MySQL 的 Server 层也有一个日志文件,叫做binlog,它可以被所有的存储引擎使用。

3. Binlog

https://dev.mysql.com/doc/refman/8.0/en/binary-log.html
binlog 以事件的形式记录了所有的 DDL 和 DML 语句(因为它记录的是操作而不是数据值,属于逻辑日志),可以用来做主从复制和数据恢复。
跟 redo log 不一样,它的文件内容是可以追加的,没有固定大小限制。
在开启了 binlog 功能的情况下,我们可以把 binlog 导出成 SQL 语句,把所有的操作重放一遍,来实现数据的恢复。
binlog 的另一个功能就是用来实现主从复制,它的原理就是从服务器读取主服务器的 binlog,然后执行一遍。

结合Binlog、redolog,一条更新SQL的执行流程:

例如一条语句:update teacher set name='盆鱼宴' wher id=1;
1、先查询到这条数据,如果有缓存,也会用到缓存。
2、把 name 改成盆鱼宴,然后调用引擎的 API 接口,写入这一行数据到内存,同时记录 redo log。这时 redo log 进入 prepare 状态,然后告诉执行器,执行完成了,可以随时提交。
3、执行器收到通知后记录 binlog,然后调用存储引擎接口,设置 redo log为 comit状态。
4、更新完成。

更新内存 -> 记录redo log(prepare) -> 写入bin log -> 事务提交更新redo log(commit)

存储引擎和server都会记日志,存储引擎记录redo log,server记录bin log;

整个更新流程

建立连接 -> 查询缓存 -> 词法/语法分析/预处理 -> 查询优化器 -> 执行引擎 --读取数据--> 存储引擎 

从磁盘/内存中读取到数据后  -> 修改数据  -> 更新内存 -> 记录日志  -> 事务提交  -> 记录日志     ---后台线程异步---  同步至磁盘
posted @ 2020-04-06 20:04  BigShen  阅读(1293)  评论(0)    收藏  举报