面试想要过关斩将,你就必须扪心自问,问得越多问的越细,才能披荆斩棘。盔甲若是漏洞百出,不被戳死才怪。
下列问题为作者提出,回答搜集而来。
由于作者并没有系统化从零开始学习MySQL,所以可能某些非常基础的问题并不了解。
欢迎读者留言比较重要的基础,wink
为了实现数据同步,通过binlog+并行复制维持数据一致性,主库应该首先启动并正常运行,然后从库再启动并连接到主库。
jdbc:mysql://database_name?socket=/temp/mysql.sck
命名管道:仅适用于win 本地连接
共享内存:另一种win特有的连接方法
默认使用TCP IP
MySQL接收到的SQL是标准的SQL语句,通常以文本的形式发给服务层
在MySQL中,默认情况下,每条单独提交的SQL语句都被视为一个独立的事务。这是因为autocommit模式下,每条语句执行完毕后会自动提交事务。如果autocommit被关闭,需要显式的 使用 BEGIN 和 COMMIT 提交事务
执行器也就是sql线程生成结果集,通过网络协议返回给客户端
typedef struct st_mysql_res
{
my_ulonglong row_count;
unsigned int field_count,current_field;
MYSQL_FIELD *fields;
MYSQL_DATA *data;
MYSQL_ROWS *data_cursor;
MEM_ROOT field_alloc;
MYSQL_ROW row;
MYSQL_ROW current_row;
unsigned long *lengths;
MYSQL *handle;
my_bool eof;
}MYSQL_RES
typedef struct st_mysql_rows
{
struct st_mysql_rows *next; //列表的行
MYSQL_ROW data;
} MYSQL_ROWS; //mysql的数据的链表节点。可见mysql的结果集是链表结构
typedef struct st_mysql_data
{
my_ulonglong rows;
unsigned int fields;
MYSQL_ROWS *data;
MEM_ROOT alloc;
} MYSQL_DATA; // 数据集的结构
typedef struct st_mysql_field
{
char *name; // 列名称
char *table; //如果列是字段,列表
char *def; //默认值(由mysql_list_fields设置)
enum enum_field_types type; //类型的字段。Se mysql_com。h的类型
unsigned int length; //列的宽度
unsigned int max_length; //选择集的最大宽度
unsigned int flags; //Div标记集
unsigned int decimals; //字段中的小数位数
} MYSQL_FIELD; //列信息的结构
typedef struct st_used_mem //结构为once_alloc
{
struct st_used_mem *next; //下一个块使用
unsigned int left; //记忆留在块
unsigned int size; //块的大小
} USED_MEM; //内存结构
typedef struct st_mem_root
{
USED_MEM *free;
USED_MEM *used;
USED_MEM *pre_alloc;
unsigned int min_malloc;
unsigned int block_size;
void (*error_handler)(void);
} MEM_ROOT; //内存结构
可以看到MySQL是用C++/C 开发的
词法分析:将SQL语句分解为一个个token
语法分析:tokens转换语法树
语义分析
解析器本身并不调用外部API,但他可能会调用内部函数或者模块来完成某些任务,例如:
元数据访问:访问系统表或缓存中的元数据,以验证表和列的存在性。
权限检查:调用权限管理模块,确保用户有足够的权限执行该操作
报错机制出现的区域:
发给客户端的形式:
{
"code":1054,
"message":"Unknown column 'nonexistent_column'in 'field list'"
}
写入日志的形式:
2025-02-27T11:41:23.123456Z 0 [ERROR] [MY-01054] Unknown column 'nonexistent_column' in 'field list'
执行器是MySQL查询处理过程中实际执行查询计划的部分。它根据优化器生成的执行计划,调用存储引擎接口来访问和修改数据。
执行器的主要职责:
1.物理操作执行:根据执行计划中的物理操作(如表扫描、索引查找等)执行相应的数据库操作。
2.数据获取与处理:从存储引擎中获取数据,并进行必要的过滤、排序、聚合等操作。
3.结果集生成:将处理后的数据组织成结果集,准备返回给客户端。
执行器的工作流程:
1.初始化执行计划:加载执行计划并准备执行环境。
2.执行物理操作:按顺序执行各个物理操作步骤。
3.返回结果
1.主线程(Main Thread)
2.连接处理线程(Connection Threads)
3.后台线程(Background Threads)
4.IO线程(I/O Threads)
5.事务处理线程(Transaction Handing Threads)
MySQL进程(mysqld)包含多个组件和模块,主要分为以下几个部分:
1.服务器核心 Server Core
3.缓存和缓冲区(Caches and Buffers)
日志系统 (Logging System)
网络层(Network Layer)
安全管理(Security Management)
执行器会通过调用存储引擎的接口来执行具体的数据库操作
调用方式:
数据页数量:
存储结构:
脏页:
数据页更新:
淘汰后的数据页清理:
LRU链表:当Buffer Pool 满时,使用LRU算法淘汰最近最少使用的页面
清理过程:
后台线程通过以下几种机制实现脏页的刷盘:
1.定时刷盘:
2.后台线程:
3.事务提交:
4.内存压力:
SQL语句的加锁操作主要在执行器和存储引擎中实现:
1.解析阶段:
2.执行器:
3.存储引擎:
SELECT * FROM users WHERE id = 1 FOR UPDATE;
执行器在执行这条查询时,会调用InnoDB的加锁接口,对users表中id=1的行加排它锁
事务在存储引擎中的实现主要包括以下几个方面:
1.事务管理器:
2.日志系统:
3.并发控制:
4.持久化:
MVCC,通过维护数据不同的版本来支持高并发下的读写操作。其主要实现机制如下:
假如有一个事务在时间点T1插入一条记录,另一个事务B在时间点T2更新了该记录。事务C在T3时间点进行读取操作时,会读取到T2时间点之前的数据版本。
Redo Log 是 InnoDB 存储引擎用于崩溃恢复的日志系统,其主要分为以下几个部分:
1.Log Blocks:
2.Log Sequence Number(LSN):
3.Checkpoint
崩溃恢复:在MySQL崩溃重启时,通过Redo Log恢复未完成的事务,确保数据的一致性。
提高性能:通过批量写入Redo Log,减少频繁的磁盘IO操作。
主要用于主从复制和数据备份。
事件类型:
格式:
Undo Log 是 InnoDB 存储引擎用于事务回滚和MVCC 的日志系统。其主要分为以下几个部分:
1.Undo Segment:每个事务分配一个Undo Segment,用于记录该事务的所有Undo日志。
2.Undo Record:每条Undo日志记录一次事务的反向操作,用于回滚和旧版本数据的构建。
事务回滚:在事务回滚时,通过Undo Log 将数据恢复到事务开始前的状态。
MVCC:提供历史版本的数据,支持高并发下的操作。
数据写磁盘的实现:
数据传输:
保证一致性:
线程角度:
线程终止:MySQL 服务器端会终止对应的连接线程,并释放相关的资源。
日志记录:断开连接的信息会被记录到错误日志中。
客户端角度:
异常处理:客户端应用程序需要捕获连接断开的异常,并进行相应的处理(如重新连接)。
超时机制:客户端可以通过设置超时参数(如 wait_timeout 和 interactive_timeout)来控制连接的有效期。
MySQL 进程结束时会执行一系列持久化操作,以确保数据的一致性和完整性:
Redo Log 刷盘:
将所有未提交的事务操作写入 Redo Log,确保在崩溃恢复时能够恢复这些事务。
Dirty Page 刷盘:
将 Buffer Pool 中的所有脏页写回到磁盘,确保数据的一致性。
Binlog 刷盘:
将 Binlog 中的所有更改操作写入磁盘,确保主从复制和数据备份的一致性。
Checkpoints:
创建 Checkpoint,标记已成功写入磁盘的数据页,加快崩溃恢复的速度。
关闭存储引擎:
关闭所有存储引擎实例,释放相关资源。
日志记录:
记录进程结束的相关信息到错误日志中,便于后续排查问题。