MySQL 架构刨根篇
01 —摘要
本文由以数据知名分享,俗话说“山高自有行客路,水深自有渡船人”。前面分享了从基础概念、数据结构、索引优化、架构设计等层面,探讨了MySQL相关知识探索之旅,今天让我们跟着小编的节奏,继续深挖MySQL神秘而又伟大的体系结构,开启MySQL刨根之程第四篇
02 — 数据库层
2.1 MySQL文件结构
2.1.1 数据库文件数据目录结构:
-
查看mysql进程:
ps -ef | grep mysql
找到datadir目录--datadir=/home/mysql/mysql/mysql/
-
观察数据库实例信息目录
cd home/mysql/mysql/mysql/
ll
-
观察某个实例的文件信息
cd mysql
ll
观察表结构文件.frm和表数据文件.ibd
2.1.2 information_schema库:
information_schema是每个MySQL实例中的一个数据库,该位置存储有关MySQL服务器维护的所有其他数据库的信息。该INFORMATION_SCHEMA数据库包含几个只读表。它们实际上是视图,而不是基表,因此没有与它们关联的文件,并且您不能对它们设置触发器
表名 | 描述 | 介绍 | 已弃用 |
CHARACTER_SETS | 可用字符集 | ||
COLLATION_CHARACTER_SET_APPLICABILITY | 适用于每个排序规则的字符集 | ||
COLLATIONS | 每个字符集的排序规则 | ||
COLUMN_PRIVILEGES | 在列上定义的权限,该信息源自mysql.columns_priv授权表 | ||
COLUMNS | 每个表中的列信息,同show columns from schema.tablename的结果 | ||
CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS | 每个帐户的当前连续失败连接尝试次数 | 5.7.17 | |
ENGINES | 存储引擎属性 | ||
EVENTS | 事件管理器事件 | ||
FILES | 存储表空间数据的文件 | ||
GLOBAL_STATUS | 全局状态变量 | ||
GLOBAL_VARIABLES | 全局系统变量 | ||
INNODB_BUFFER_PAGE | InnoDB 缓冲池中的页面 | ||
INNODB_BUFFER_PAGE_LRU | InnoDB 缓冲池中页面的 LRU 排序 | ||
INNODB_BUFFER_POOL_STATS | InnoDB 缓冲池统计信息 | ||
INNODB_CMP | 与压缩 InnoDB 表相关的操作状态 | ||
INNODB_CMP_PER_INDEX | 与压缩 InnoDB 表和索引相关的操作状态 | ||
INNODB_CMP_PER_INDEX_RESET | 与压缩 InnoDB 表和索引相关的操作状态 | ||
INNODB_CMP_RESET | 与压缩 InnoDB 表相关的操作状态 | ||
INNODB_CMPMEM | InnoDB 缓冲池中压缩页面的状态 | ||
INNODB_CMPMEM_RESET | InnoDB 缓冲池中压缩页面的状态 | ||
INNODB_FT_BEING_DELETED | INNODB_FT_DELETED 表的快照 | ||
INNODB_FT_CONFIG | InnoDB 表 FULLTEXT 索引和相关处理的元数据 | ||
INNODB_FT_DEFAULT_STOPWORD | InnoDB FULLTEXT 索引的默认停用词列表 | ||
INNODB_FT_DELETED | 从 InnoDB 表 FULLTEXT 索引中删除的行 | ||
INNODB_FT_INDEX_CACHE | InnoDB FULLTEXT 索引中新插入行的令牌信息 | ||
INNODB_FT_INDEX_TABLE | 针对 InnoDB 表 FULLTEXT 索引处理文本搜索的倒排索引信息 | ||
INNODB_LOCK_WAITS | InnoDB 事务锁等待信息 | 5.7.14 | |
INNODB_LOCKS | InnoDB 事务锁信息 | 5.7.14 | |
INNODB_METRICS | InnoDB 性能信息 | ||
INNODB_SYS_COLUMNS | 每个 InnoDB 表中的列 | ||
INNODB_SYS_DATAFILES | InnoDB file-per-table 和通用表空间的数据文件路径信息 | ||
INNODB_SYS_FIELDS | InnoDB 索引的关键列 | ||
INNODB_SYS_FOREIGN | InnoDB 外键元数据 | ||
INNODB_SYS_FOREIGN_COLS | InnoDB 外键列状态信息 | ||
INNODB_SYS_INDEXES | InnoDB 索引元数据 | ||
INNODB_SYS_TABLES | InnoDB 表元数据 | ||
INNODB_SYS_TABLESPACES | InnoDB file-per-table、通用和撤消表空间元数据 | ||
INNODB_SYS_TABLESTATS | InnoDB 表低级状态信息 | ||
INNODB_SYS_VIRTUAL | InnoDB 虚拟生成列元数据 | ||
INNODB_TEMP_TABLE_INFO | 有关活动用户创建的 InnoDB 临时表的信息 | ||
INNODB_TRX | 活动 InnoDB 事务信息 | ||
KEY_COLUMN_USAGE | 哪些键列有约束 | ||
MYSQL_FIREWALL_USERS | 帐户配置文件的防火墙内存数据 | ||
MYSQL_FIREWALL_WHITELIST | 帐户配置文件许可名单的防火墙内存数据 | ||
ndb_transid_mysql_connection_map |
该表提供了NDB事务,NDB事务协调器(coordinators)以及附加在NDB中的MySQL数据库之间的映射关系 |
||
OPTIMIZER_TRACE | 优化器跟踪活动产生的信息 | ||
PARAMETERS | 存储的例程参数和存储的函数返回值 | ||
PARTITIONS | 表分区信息 | ||
PLUGINS | 插件信息 | ||
PROCESSLIST | 查询当前正在执行的线程的信息,如查询活跃线程信息: select id, db, user, host, command, time, state, info from information_schema.processlist where command != 'Sleep' order by time desc; | ||
PROFILING | 语句分析信息 | ||
REFERENTIAL_CONSTRAINTS | 外键信息 | ||
ROUTINES | 存储的常规信息 | ||
SCHEMA_PRIVILEGES | 在数据库实例上定义的权限,该信息来自mysql.db授权表 | ||
SCHEMATA | 当前mysql实例中所有数据库的信息。与show databases结果对应 | ||
SESSION_STATUS | 当前会话的状态变量 | ||
SESSION_VARIABLES | 当前会话的系统变量 | ||
STATISTICS | 表索引统计,show index from schema.tablename的结果 | ||
TABLE_CONSTRAINTS | 哪些表有约束 | ||
TABLE_PRIVILEGES | 在表上定义的权限,该信息源自mysql.tables_priv授权表 | ||
TABLES | 表信息(包含视图),详细表述了某个表属于哪个schema、表类型、表引擎、创建时间等信息。同show tables from schema的结果 | ||
TABLESPACES | 表空间信息 | ||
TP_THREAD_GROUP_STATE | 线程池线程组状态 | ||
TP_THREAD_GROUP_STATS | 线程池线程组统计 | ||
TP_THREAD_STATE | 线程池线程信息 | ||
TRIGGERS | 触发器信息 | ||
USER_PRIVILEGES | 用户权限信息表,该信息源自mysql.user授权表 | ||
VIEWS | 查看视图信息 |
2.1.3 performance_schema库:
MySQL 5.5后新增的一个数据库:performance_schema,主要用于收集数据库服务器性能参数。且该库所有表的存储引擎均为performance_schema,具体可以参考MySQL官方文档。MySQL5.5默认是关闭的,需要手动开启,在配置文件里添加:
[mysqld]
performance_schema=ON
-
设置表(setup_*):这些表用于配置和显示监控特性。
-
当前事件表(events_*_current):该
events_waits_current
表包含每个线程的最新事件。其他类似的表包含事件层次结构不同级别的当前事件:events_stages_current
阶段事件、events_statements_current
语句事件和events_transactions_current
事务事件。 -
历史表(events_*_history_*):这些表与当前事件表具有相同的结构,但包含更多行。例如,对于等待事件,
events_waits_history
表包含每个线程最近的 10 个事件。events_waits_history_long
包含最近的 10,000 个事件。其他类似的表存在于阶段、语句和事务历史中。要更改历史表的大小,请在服务器启动时设置适当的系统变量。例如,要设置等待事件历史记录表的大小,请设置performance_schema_events_waits_history_size
和performance_schema_events_waits_history_long_size
。 -
汇总表(events_*_summary_*):这些表包含在事件组上聚合的信息,包括那些已从历史表中丢弃的信息。
-
实例表(*_instances_*):这些表记录了检测的对象类型。被检测的对象在被服务器使用时会产生一个事件。这些表提供事件名称和解释性说明或状态信息。
-
其他表:*。
2.1.4 mysql系统库
该mysql数据库是系统数据库。它包含存储 MySQL 服务器运行时所需信息的表。mysql数据库中的表分为以下几类:权限系统表、对象信息系统表、日志系统表、服务器端帮助系统表、时区系统表、复制系统表、优化器系统表和其他系统表
2.1.4.1 权限系统表
这些系统表包含有关用户帐户及其拥有的权限的授权信息:
-
user:包含用户账户、全局权限和其他非权限列表(安全配置字段和资源控制字段)。
-
db:数据库级别的权限表。
-
tables_priv:表级别的权限表。
-
columns_priv:字段级别的权限表。
-
procs_priv:存储过程和函数权限表。
-
proxies_priv:代理用户权限表。
2.1.4.2 对象信息系统表
这些系统表包含有关存储程序、可加载函数和服务器端插件的信息:
-
event:使用CREATE EVENT. 如果使用该--skip-grant-tables选项启动服务器 ,则事件调度程序被禁用并且表中注册的事件不会运行。
-
func:使用 CREATE FUNCTION. 在正常启动序列期间,服务器加载此表中注册的函数。如果使用该--skip-grant-tables选项启动服务器 ,则表中注册的函数不会加载且不可用。
-
plugin:使用INSTALL PLUGIN. 在正常启动序列期间,服务器加载在此表中注册的插件。如果使用该--skip-grant-tables选项启动服务器 ,则表中注册的插件不会加载且不可用。该表在MySQL 5.7.6使用的是MyISAM存储引擎,之后是InnoDB存储引擎。
-
proc:有关存储过程和函数的信息。
2.1.4.3 日志系统表
服务器使用以下系统表进行日志记录,日志表使用CSV存储引擎:
-
general_log: 一般查询日志表。
-
slow_log: 慢查询日志表。
2.1.4.4 服务器端帮助系统表
这些系统表包含服务器端帮助信息,在MySQL 5.7.5之前使用的是MyISAM存储引擎,之后使用InnoDB存储引擎 :
-
help_category:有关帮助类别的信息。
-
help_keyword:与帮助主题相关的关键字。
-
help_relation:帮助关键字和主题之间的映射。
-
help_topic: 帮助主题内容。
2.1.4.5 时区系统表
这些系统表包含时区信息,在MySQL 5.7.5之前使用的是MyISAM存储引擎,之后使用InnoDB存储引擎 :
-
time_zone:时区 ID 以及它们是否使用闰秒。
-
time_zone_leap_second:闰秒发生时。
-
time_zone_name:时区 ID 和名称之间的映射。
-
time_zone_transition, time_zone_transition_type: 时区说明。
2.1.4.6 复制系统表
服务器使用这些系统表来支持复制:
-
gtid_executed:用于存储 GTID 值的表。该表使用 InnoDB存储引擎。
-
ndb_binlog_index:NDB Cluster 复制的二进制日志信息。
在 NDB 7.5.2 之前,该表使用 MyISAM存储引擎。在 NDB 7.5.2 及更高版本中,它使用 InnoDB. 如果您计划从 NDB Cluster 先前版本升级到 NDB 7.5.2 或更高版本 -
slave_master_info, slave_relay_log_info, slave_worker_info: 用于在副本服务器上存储复制信息。这三个表都使用InnoDB 存储引擎。
2.1.4.7 优化器系统表
这些系统表供优化器使用,使用InnoDB存储引擎:
-
innodb_index_stats, innodb_table_stats: 用于InnoDB持久优化器统计信息。
-
server_cost, engine_cost: 优化器成本模型使用的表包含有关查询执行期间发生的操作的成本估计信息。server_cost包含一般服务器操作的优化器成本估算。engine_cost包含对特定存储引擎特定操作的估计。
2.1.4.8 其他系统表
其他系统表不属于上述类别:
-
audit_log_filter, audit_log_user: 如果安装了MySQL Enterprise Audit,这些表提供审计日志过滤器定义和用户帐户的持久存储。
-
firewall_users, firewall_whitelist: 如果安装了MySQL Enterprise Firewall,这些表为防火墙使用的信息提供持久存储。
-
servers: 由 FEDERATED存储引擎使用。
该servers表在MySQL 5.7.6之前使用MyISAM是存储引擎,之后使用的是InnoDB存储引擎 。
2.1.5 sys系统库
MySQL 5.7 包含 sys模式,这是一组帮助 DBA 和开发人员解释性能模式收集的数据的对象。sys模式对象可用于典型的调优和诊断用例。此架构中的对象包括:
-
将 Performance Schema 数据汇总为更易于理解的形式的视图。
-
执行性能模式配置和生成诊断报告等操作的存储过程。
-
查询性能架构配置并提供格式化服务的存储函数。
2.1.6 日志组文件
在MySQL的数据目录下存在日志组文件: ib_logfile0、ib_logfile1....,默认均为5M
2.1.7 表结构文件:*.frm
在MYSQL中建立任何一张数据表,在其数据存放目录对应的数据库目录下都有对应表的.frm文件, .frm文件是用来保存每个数据表的元数据(meta)信息,包括表结构的定义等,
在MySQL中,“.frm”文件跟数据库存储引擎无关,任何存储引擎的数据表结构文件都存储为.frm文件,命名方式为“tablename.frm”,如user.frm,.frm文件可以用来在数据库崩溃时恢复表结构。
2.1.8 独占表空间文件:*.ibd
在innodb_file_per_table配置为ON时设置为独占表空间,此时,系统将为每一个表单独存储为“.ibd”文件,(如user.ibd)在此文件中,存储与该表相关的数据、索引、表的内部数据字典信息。
2.1.9 字符集和排序规则文件:db.opt
文件中记录了该库的默认字符集编码和字符集排序规则。如果你创建数据库指定默认字符集和排序规则,后续创建的表如果没有指定字符集和排序规则,那么该新建的表将采用db.opt文件中指定的属性。
如果删除这个db.opt,MySQL在建表时将参照全局的字符设置,即default-character-set ,这个影响是在建表的时候才会有体现。
[root@ecs-prod-my57-fsolap-ro base]# cat db.opt default-character-set=utf8 default-collation=utf8_general_ci
03 — 存储引擎层
3.1 Innodb体系结构
3.1.1、MVCC
Multi-Version Concurrency Control,即多版本的并发控制协议。是一种用来解决读-写冲突的无锁并发控制,主要依赖记录中的 3个隐式字段,undo日志,Read View来实现。也就是为事务分配单向增长的时间戳,为每个修改保存一个版本,版本与事务时间戳关联,读操作只读该事务开始前的数据库的快照数据。
在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能。
同时还可以解决脏读,幻读,不可重复读等事务隔离问题,但不能解决数据更新丢失问题。
3.1.2 事务
3.1.2.1 ACID属性
-
原子性(Atomicity):事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行。
-
一致性(Consistent) :在事务开始和完成时,数据都必须保持一致状态。这意味着所有相关的数据规则都必须应用于事务的修改,以保持数据的完整性。
-
隔离性(Isolation) :数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境执行。这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然。
-
持久性(Durable) :事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。
3.1.2.2 产生问题
-
更新丢失(Lost Update)或脏写:最后的更新覆盖了由其他事务所做的更新。
-
脏读(Dirty Reads):事务A读取到了事务B已经修改但尚未提交的数据
-
不可重读(Non-Repeatable Reads):事务A内部的相同查询语句在不同时刻读出的结果不一致,不符合隔离性
-
幻读(Phantom Reads):事务A读取到了事务B提交的新增数据,不符合隔离性
3.1.2.3 隔离级别
3.1.3 锁
锁是计算机协调多个进程或线程并发访问某一资源的机制(保证系统数据访问的一致性)。
3.1.3.1 锁的分类
-
从性能上分为乐观锁(用版本对比来实现)和悲观锁
-
从对数据库操作的类型分,分为读锁和写锁(都属于悲观锁)
读锁(共享锁,S锁(Shared)):针对同一份数据,多个读操作可以同时进行而不会互相影响
写锁(排它锁,X锁(eXclusive)):当前写操作没有完成前,它会阻断其他写锁和读锁
读锁会阻塞写,但是不会阻塞读。而写锁则会把读和写都阻塞
-
从对数据操作的粒度分,分为表锁和行锁
3.1.3.2 死锁原因
原因:死锁的关键在于:两个(或以上)的Session加锁的顺序不一致。
解决:让不同的session加锁有次序
04 — 表空间层
4.1 表空间结构
4.1.1 Segment
数据段为B+树的叶子节点,索引段即为B+树的非叶子节点InnoDB存储引擎的管理是由引擎本身完成的,表空间(Tablespace)是由分散的段(Segment)组成。一个段(Segment)包含多个区(Extent)。
4.1.2 Extent
区由64个连续的页(Page)组成,每个页大小为16K,即每个区大小为1MB,创建新表时,先使用32页大小的碎片页存放数据,使用完后才是区的申请(InnoDB最多每次申请4个区,保证数据的顺序性能)
4.1.3 Page
分为数据页、Undo页、系统页、事务数据页、插入缓冲位图页、以及插入缓冲空闲列表页。
Tips:磁盘存储容量=磁头数×磁道(柱面)数×每道扇区数×每扇区字节数
4.2 共享表空间
4.2.1 定义
Innodb的所有数据保存在一个单独的表空间里面,而这个表空间可以由很多个文件组成,一个表可以跨多个文件存在,所以其大小限制不再是文件大小的限制,而是其自身的限制。从Innodb的官方文档中可以看到,其表空间的最大限制为64TB,也就是说,Innodb的单表限制基本上也在64TB左右了,当然这个大小是包括这个表的所有索引等其他相关数据。
4.2.2 优点
可以把表空间分成多个文件存放到各个磁盘上(表空间文件大小不受表大小的限制,如一个表可以分布在不同步的文件上)。数据和文件放在一起方便管理。
4.3 独立表空间
4.3.1 定义
每一个表都将会生成以独立的文件方式来进行存储,每一个表都有一个.frm表描述文件,还有一个.ibd文件. 其中这个文件包括了单独一个表的数据内容以及索引内容,默认情况下它的存储位置也是在表的位置之中。
这个时候的单表限制,又变成文件系统的大小限制了。在配置文件(my.cnf)中设置:innodb_file_per_table 即可设置为独立表空间
4.3.2 优点
-
每个表都有自已独立的表空间。
-
每个表的数据和索引都会存在自已的表空间中。
-
可以实现单表在不同的数据库中移动。
-
空间可以回收(除drop table操作处,表空不能自已回收)
-
Drop table操作自动回收表空间,如果对于统计分析或是日值表,删除大量数据后可以通过:alter table TableName engine=innodb;回缩不用的空间。
-
对于使用独立表空间的表,不管怎么删除,表空间的碎片不会太严重的影响性能,而且还有机会处理。
-
对于使innodb-plugin的Innodb使用turncate table也会使空间收缩。
05 — 执行逻辑层
5.1 逻辑架构
客户端发出一条DML语句,经过服务层解析引擎解析,再到存储引擎缓存池等等一些列的MVCC事务链路,触发的端到端的数据查询血缘链路。
具体过程如下图:
具体操作流程如下:
-
1、客户端发起DML请求
-
2、服务端调用存储引擎对应操作接口
-
3、存储引擎从磁盘文件加载缓存数据,加载对应id的记录所在的整页数据
-
4、存储引擎写入更新数据的旧值到undo日志文件,偏于回滚
-
5、服务端更新最新数据到缓存池,同时写redo日志到存储引擎层的redo log buffer
-
6、redo log buffer准备提交事务redo日志,并写入数据到磁盘redo日志文件
-
7、服务端准备提交事务binlog日志,并写入数据到磁盘binlog文件。主要用来恢复数据库磁盘里的数据
-
8、服务端写入commit标识到磁盘redo日志文件里,提交事务完成。该标记为了保证事务提交后redo和binlog文件数据一致
-
9、存储引擎层缓存池修改数据,并通过IO线程,随机写入磁盘,以page为单位写入,完成整个事务过程
06 — 总结
“渡人者自渡,自渡者天渡”,让我们同小编一起,心怀“不为已甚,不存芥蒂”之心,有条不紊的找到我们的登山行客之路,循序渐进的成为我们的跨海摆渡之人!
出自https://www.modb.pro/db/69701