文章目录
- 第一章 `MySQL`体系结构和存储引擎
- 前言
- 1.1 定义数据库和实例
- 1.2`MySQL`体系结构
- 1.3`MySQL`存储引擎
- 1.3.1`InnoDB`存储引擎
- 1.3.2`MyISAM`存储引擎
- 1.3.3`NDB`存储引擎
- 1.3.4 `Memory`存储引擎
- 1.3.5其他存储引擎
- 1.4各存储引擎之间的比较
- 1.5连接`MySQL`
- 1.5.1 `TCP/IP`
- 1.5.2命名管道和共享内存
- 1.5.3`UNIX`域套接字
第一章 MySQL
体系结构和存储引擎
最近在学习MySQL
数据库,主要是先学习一些MySQL
的一些基本SQL
语句。但是呢,我也知道仅仅是掌握这些是远远不够的,因此在学习基础知识的同时我也在看MySQL
稍微深入一点的一本书《MySQL技术内幕 InnoDB存储引擎》(第二版) 姜成尧著
。因此本系列博客主要内容来自于这本书,以及包括一些我在阅读这本书的过程中的一些实际操作验证和读后感等。本篇博客主要出自第一章 MySQL
体系结构和存储引擎。在后期的章节中,根据不同章节所含知识的容量及其难度,会拆分成多篇博客产出。
前言
MySQL
被设计为一个可移植的数据库,几乎在当前所有系统上都能运行,如Linux,Solaris,FreeBSD,Mac和Windows
。尽管各平台在底层(如线程)实现方面都各有不同,但是MySQL
基本上能保证在各平台上的物理体系结构的一致性。因此,用户应该能很好地理解MySQL
数据库在所有这些平台上是如何运作的。
1.1 定义数据库和实例
数据库和实例分别是什么?一样吗?作为常见的数据库术语,这两个词定义如下。
- 数据库:物理操作系统文件或其他形式文件类型的集合。在
MySQL
数据库中,数据库文件可以是frm、MYD、MYI、ibd
结尾的文件【1验证】。当使用NDB
引擎时,数据库的文件可能不是操作系统上的文件,而是存放与内存之中的文件,但是定义仍然不变。 - 实例:
MySQL
数据库由后台线程以及一个共享内存区组成。共享内存可以被运行的后台线程所共享。共享内存可以被运行的后台线程所共享。需要牢记的是,数据库实例才是真正用于操作数据库文件的。
【1验证】
MySQL
数据库是都会有一个配置文件(后续会讲到),配置文件包含了MySQL
编译时的默认参数设置。在配置文件中有一行存储路径是用来表示数据库文件的物理存储路径的。在Linux
操作系统下,配置文件路径是/etc/my.cnf
【注意这里由于是系统级文件,需要使用root
权限访问】在配置文件中,datadir
正是表示数据库文件的物理存储路径的。[root@VM-20-12-centos mysql]# cat /etc/my.cnf # For advice on how to change settings please see # http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html [mysqld] # # Remove leading # and set to the amount of RAM for the most important data # cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%. # innodb_buffer_pool_size = 128M # # Remove leading # to turn on a very important data integrity option: logging # changes to the binary log between backups. # log_bin # # Remove leading # to set options mainly useful for reporting servers. # The server defaults are faster for transactions and fast SELECTs. # Adjust sizes as needed, experiment to find the optimal values. # join_buffer_size = 128M # sort_buffer_size = 2M # read_rnd_buffer_size = 2M `datadir=/var/lib/mysql` socket=/var/lib/mysql/mysql.sock # Disabling symbolic-links is recommended to prevent assorted security risks symbolic-links=0 log-error=/var/log/mysqld.log pid-file=/var/run/mysqld/mysqld.pid skip-grant-tables character-set-server=utf8 default-storage-engine=innodb
当我们进入到这个路径下时,我们就可以看到数据库中的文件。我们进入任意一个数据库,就可以看到很多
.frm,.MYD结尾的文件
。[root@VM-20-12-centos mysql]# cd 104_db_lesson3 [root@VM-20-12-centos 104_db_lesson3]# ll total 992 -rw-r----- 1 mysql mysql 8614 Apr 12 08:14 class.frm -rw-r----- 1 mysql mysql 98304 Apr 12 08:15 class.ibd -rw-r----- 1 mysql mysql 61 Apr 12 08:03 db.opt -rw-r----- 1 mysql mysql 8605 Apr 12 09:23 student.frm -rw-r----- 1 mysql mysql 114688 Apr 12 09:24 student.ibd -rw-r----- 1 mysql mysql 8588 Apr 12 08:17 t1.frm -rw-r----- 1 mysql mysql 98304 Apr 12 08:18 t1.ibd -rw-r----- 1 mysql mysql 8588 Apr 12 08:21 t2.frm -rw-r----- 1 mysql mysql 98304 Apr 12 08:21 t2.ibd -rw-r----- 1 mysql mysql 8632 Apr 12 08:30 t3.frm -rw-r----- 1 mysql mysql 98304 Apr 12 08:30 t3.ibd -rw-r----- 1 mysql mysql 8578 Apr 12 08:41 t4.frm -rw-r----- 1 mysql mysql 98304 Apr 12 08:42 t4.ibd -rw-r----- 1 mysql mysql 8601 Apr 12 08:57 t5.frm -rw-r----- 1 mysql mysql 98304 Apr 12 08:57 t5.ibd -rw-r----- 1 mysql mysql 8620 Apr 12 09:00 t6.frm -rw-r----- 1 mysql mysql 98304 Apr 12 09:02 t6.ibd -rw-r----- 1 mysql mysql 8586 Apr 12 09:08 t7.frm -rw-r----- 1 mysql mysql 98304 Apr 12 09:09 t7.ibd
这两个词被设计为一个单进程多线程架构的数据库,说白了,MySQL
数据库实例在系统上的表示就是一个进程。
在Linux操作系统中通过命令可以启动MySQL
数据库实例,通过ps
命令可以观察MySQL
数据库启动后的进程情况:
[root@VM-20-12-centos 104_db_lesson3]# ps -aux| grep mysqld
mysql 17022 0.0 9.3 1514312 192008 ? Sl Apr06 3:43 /usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid
字段解释:
USER:创建进程的用户
PID:进程ID
%CPU:进程占用CPU的百分比
%MEM:进程占用物理内存的百分比
VSZ:进程占用虚拟内存的大小(单位KB)
RSS:进程占用实际物理内存的大小(单位KB)
TTY:进程在哪个终端运行。
STAT:进程状态
START:进程开始启动的时间
TIME:进程使用的CPU(运算)时间
COMMAND:调用进程的命令
这个进程号为17022的进程,该进程就是MySQL
的实例。当启动实例时,MySQL
数据库会去读取配置文件,根据配置文件的参数来启动数据库实例。在MySQL
数据库中,可以没有配置文件,在这种情况下,MySQL
会按照编译时的默认参数设置启动实例。用下面这个命令可以查看当MySQL
数据库实例启动时,会在那些位置查找配置文件。
[root@VM-20-12-centos 104_db_lesson3]# mysql --help | grep my.cnf
order of preference, my.cnf, $MYSQL_TCP_PORT,
/etc/my.cnf /etc/mysql/my.cnf /usr/etc/my.cnf ~/.my.cnf
可以看到,MySQL
数据库是按照/etc/my.cnf /etc/mysql/my.cnf /usr/etc/my.cnf ~/.my.cnf
的顺序读取配置文件的。当有多个配置文件中都有同一个参数,MySQL
数据库会以读取到最后一个配置文件中的参数为准。在Linux
环境下,配置文件一般会放在/ect/my.cnf
下。在Windows
环境下,配置文件的后缀名可能是.cnf
或.ini
。例如在Windows
操作系统下运行mysql--help
可以看到以下内容(如下展示的为我Windows
系统安装的MySQL
)
Default options are read from the following files in the given order:
C:\WINDOWS\my.ini C:\WINDOWS\my.cnf C:\my.ini C:\my.cnf C:\Program Files\MySQL\MySQL Server 8.0\my.ini C:\Program Files\MySQL\MySQL Server 8.0\my.cnf
1.2MySQL
体系结构
在上一节我们提到了我不能把MySQL
既理解是数据库,也是数据库实例。从概念上来说,数据库是文件的集合,是依照某种数据模型组织起来并存放于二级存储器中的数据集合;数据库实例是程序,是位于用户与操作系统之间的一层数据管理软件,用户对数据库数据的任何操作,包括数据库定义,数据查询,数据维护,数据库运行控制等都是在数据库实例下进行的,应用程序只有通过数据库实例才能和数据库打交道。
如果这样还不是很好理解,用一种直白的方式进行解释:数据库是由一个个文件组成(一般来说都是二进制的文件)的,要对这些文件执行诸如SELECT,INSERT,UPDATE和DELETE
之类的数据库操作是不能通过简单的操作文件来更改数据库的内容,需要通过数据库实例来完成对数据库的操作。所以,用户把MySQL
简单的理解成数据库可能有失偏颇的,虽然在实际使用中并不会这么强调两者之间的区别。在了解复杂枯燥的定义之后,现在来看看MySQL
数据库的体系结构[如图1.2-1]
从图[1.2-1]可以发现,MySQL
由以下几个部分组成:
- 连接池组件
- 管理服务和工具组件
SQL
接口组件- 查询分析器组件
- 优化器组件
- 缓冲
Cache
组件 - 插件式存储引擎
- 物理文件
MySQL
数据库区别于其他数据库的最重要的一个特点就是其插件式的表存储引擎。MySQL
插件式的存储引擎架构提供了一系列标准的管理和服务支持,这些标准与存储引擎本身无关,可能是每个数据库系统本身都必需的,如SQL
分析器和优化器等,而存储引擎是底层物理结构的实现,每个存储引擎开发者可以按照自己的意愿来进行开发。需要特别注意的是,存储引擎是基于表的,而不是数据库.
1.3MySQL
存储引擎
通过1.2节大致了解了MySQL
数据库独有的插件式体系结构,并了解到存储引擎是MySQL
区别于其他数据库的一个最重要特性。存储引擎的好处是,每个存储引擎都有各自的特点,能够根据具体的应用建立不同存储引擎表。对于开发人员来说,存储引擎对其是透明的,但了解各种存储引擎的区别对于开发人员来说也是有好处的。
1.3.1InnoDB
存储引擎
InnoDB
存储引擎支持事务,其设计目的主要面向在线事务处理(OLTP
)的应用。其特点是行锁设计,支持外键,并支持非锁定读。即默认读取不会产生锁。从MySQL数据库5.5.8
版本开始,InnoDB
存储引擎是默认的存储引擎。
InnoDB
存储引擎将数据放在一个逻辑的表空间中,这个表空间就像黑盒一样由InnoDB
存储引擎自身进行管理。从MySQL4.1(包括4.1)
版本开始,它可以将每个InnoDB
存储引擎的表单独存放在一个ibd
文件中。此外,InnoDB
存储引擎支持用裸设备(row disk
)用来建立其表空间。
InnoDB
通过使用多版本并发控制(MVCC
)来获得高并发性,并且实现了SQL
标准的4中隔离级别,默认为REPEATABLE
级别。同时,使用一种被称为next-key-locking
的策略来避免幻读phantom
现象的产生。除此之外,InnoDB
存储引擎还提供了插入缓存insert buffer
,二次写double write
,自适应哈希索引adaptive hash index
,预读read ahead
等高性能和高可用的功能。
对于表中数据的存储,InnoDB
存储引擎采用了聚集clustered
的方式,因此每张表的存储都是按主键的顺序进行存放。如果没有显式地在表定义时指定主键,InnoDB
存储引擎会为每一行生成一个6字节地ROWID
,并以此作为主键。
1.3.2MyISAM
存储引擎
MyISAM
存储引擎不支持事务,表锁设计,支持全文索引,主要面向一些OLAP
数据库应用。在MySQL5.5.8
版本之前MyISAM
存储引擎时默认的存储引擎(除Windows
版本之外)。数据库系统与文件系统很大的一个不同之处在于对事务的支持,然而MyISAM
存储引擎是不支持事务的。究其根本,这也不是很难理解。试想用户是否在所有的应用中都需要事务呢?答案是非也。在数据库仓库中,如果欸有ETL
这些操作,只是简单的报表查询是否还需要事务的支持呢?此外,MyISAM
存储引擎的另一个与众不同的地方是它的缓冲池只缓存cache
索引文件,而不缓冲数据文件,这点和大多数的数据库都非常不同。
MyISAM
存储引擎表由MYD
和MYI
组成,MYD
用来存放数据文件,MYI
用来存放索引文件。在MySQL 5.0
版本之前,MyISAM
默认支持的表大小为4GB
,如果需要支持大于4GB
的MyISAM
表时,则需要制定MAX_ROWS
和AVG_ROW_LENGTH
属性。从MySQL 5.0
版本开始,MyISAM
默认支持256TB
的表单数据,这足够满足一般应用需求。
注意:对于
MyISAM
存储引擎表,MySQL
数据库只缓存其索引文件,数据文件的缓存交由操作系统本身来完成,这与其它使用LRU
算法缓存数据的大部分数据库大不相同。此外,在MySQL 5.1.23
版本之前。无论是在32位还是64位操作系统环境下,缓存索引的缓冲区最大只能设置为4GB
。在之后的版本中,64位系统可以支持大于4GB
的索引缓冲区。
1.3.3NDB
存储引擎
NDB
存储引擎是一个集群存储引擎。NDB
的特点是数据全部放在内存中(从MySQL5.1
版本开始,可以将非索引数据放在磁盘上),因此主键查找速度极快,并且通过添加NDB
数据存储节点可以线性地提高数据库性能,是高可用,高性能地集群系统。
NDB
存储引擎的连接操作是在MySQL
数据库层完成的,而不是在存储引擎层完成的。这意味着,复杂的连接操作需要巨大的网络开销,因此查询速度很慢。
1.3.4 Memory
存储引擎
Memory
存储引擎将表中的数据存放在内存中,如果数据库重启或发生崩溃,表中的数据都将丢失。它非常适合于存储临时数据的临时表,以及数据仓库中的维度表。Memory
存储引擎默认使用哈希索引,而不是我们B+树
索引。
虽然Memory
存储引擎速度非常快,但在使用上还是有一定的限制。比如,只支持表锁,并发性能较差,并且不支持TEXT
和BLOB
列类型。最重要的是,存储变长字段(varchar)
时是按照定常字段(char)
的方式进行的,因此会浪费内存。
此外有一点容易被忽视,MySQL
数据库使用Memory
存储引擎作为临时表来存放查询的中间结果集。如果中间结果集大于Memory
存储引擎表的容量设置,又或者中间结果含有TEXT
或BLOB
列类型字段,则MySQL
数据库会把其转换到MyISAM
存储引擎表而存放到磁盘中。之前提到的MyISAM
不缓存数据文件,因此这时产生的临时表的性能对于查询会有损失。
1.3.5其他存储引擎
除了上面提到的这几种存储引擎,MySQL
数据库还有很多其他的存储引擎,他们都有各自使用的场合,这里不再一一介绍。在了解了MySQL
的多种存储引擎后我们回答
-
为什么
MySQL
数据库不支持全文索引? 不!MySQL
支持,MyISAM,InnoDB和Sphinx
存储引擎都支持全文索引。 -
MySQL
数据库速度快是因为不支持事务? 错!虽然MySQL
的MyISAM
存储引擎不支持事务,但是InnoDB
支持。"快"是相对于不同应用来说,对于ETL
这种操作,MyISAM
会有其优势,但在OLTP
环境中,InnoDB
存储引擎的效率更好 -
当表的数据量大于1000万时
MySQL
的性能会急剧下降吗? 不!MySQL
是数据库,不是文件,随着数据行数的增加,性能当然会有所下降,但是这些下降不是线性的,如果用户选择了正确的存储引擎,以及正确的配置,再多的数据量MySQL
也能承受。如官方手册上提及到的,Mytrix
和Inc
在InnoDB
上存储超过1TB
的数据,还有一些其他网站使用InnoDB
存储引擎,处理插入/更新的操作平均800次/秒。
1.4各存储引擎之间的比较
通过1.3节的介绍,我们了解了存储引擎是MySQL
体系结构的核心。这里将通过简单比较几个存储引擎来让读者更直观地理解存储引擎地概念。图1-2取于MySQL
的官方手册,展现了一些常用MySQL
存储引擎之间的不同之处,包括存储容量的限制,事务支持,锁的粒度,MVCC
支持,支持的索引,备份和复制等。
通过SHOW ENGINES
语句查看当前使用的MySQL
数据库所支持的存储引擎,也可以通过查找information_schema
架构下的ENGINES
表
mysql> show engines;
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| Engine | Support | Comment | Transactions | XA | Savepoints |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| InnoDB | DEFAULT | Supports transactions, row-level locking, and foreign keys | YES | YES | YES |
| MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO |
| MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO |
| BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears) | NO | NO | NO |
| MyISAM | YES | MyISAM storage engine | NO | NO | NO |
| CSV | YES | CSV storage engine | NO | NO | NO |
| ARCHIVE | YES | Archive storage engine | NO | NO | NO |
| PERFORMANCE_SCHEMA | YES | Performance Schema | NO | NO | NO |
| FEDERATED | NO | Federated MySQL storage engine | NULL | NULL | NULL |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
9 rows in set (0.02 sec)
mysql> show engines \G
*************************** 1. row ***************************
Engine: InnoDB
Support: DEFAULT
Comment: Supports transactions, row-level locking, and foreign keys
Transactions: YES
XA: YES
Savepoints: YES
*************************** 2. row ***************************
Engine: MRG_MYISAM
Support: YES
Comment: Collection of identical MyISAM tables
Transactions: NO
XA: NO
Savepoints: NO
*************************** 3. row ***************************
Engine: MEMORY
Support: YES
Comment: Hash based, stored in memory, useful for temporary tables
Transactions: NO
XA: NO
Savepoints: NO
*************************** 4. row ***************************
Engine: BLACKHOLE
Support: YES
Comment: /dev/null storage engine (anything you write to it disappears)
Transactions: NO
XA: NO
Savepoints: NO
*************************** 5. row ***************************
Engine: MyISAM
Support: YES
Comment: MyISAM storage engine
Transactions: NO
XA: NO
Savepoints: NO
*************************** 6. row ***************************
Engine: CSV
Support: YES
Comment: CSV storage engine
Transactions: NO
XA: NO
Savepoints: NO
*************************** 7. row ***************************
Engine: ARCHIVE
Support: YES
Comment: Archive storage engine
Transactions: NO
XA: NO
Savepoints: NO
*************************** 8. row ***************************
Engine: PERFORMANCE_SCHEMA
Support: YES
Comment: Performance Schema
Transactions: NO
XA: NO
Savepoints: NO
*************************** 9. row ***************************
Engine: FEDERATED
Support: NO
Comment: Federated MySQL storage engine
Transactions: NULL
XA: NULL
Savepoints: NULL
9 rows in set (0.00 sec)
1.5连接MySQL
本节将介绍连接MySQL
数据库的常用方式。需要理解的是,连接MySQL
操作时一个连接进程和MySQL
数据库实例进行通信。从程序设计的角度来说,本质上是进程通信。如果对进程通信比较了解,可以知道常用的进程通信方式有管道,命名管道,命名字,TCP/IP
套接字,UNIX
域套接字。MySQL
数据库提供的连接方式从本质上看都是上述提及的进程通信方式。
1.5.1 TCP/IP
TCP/IP
套接字方式是MySQL
数据库在任何平台下都提供的连接方式,也是网络中使用的最多的一种方式。这种方式在TCP/IP
连接上一个基于网络的连接请求,一般情况下客户端(client
)在一台服务器上,而MySQL实例(server)
在另一台服务器上,这两台机器通过一个TCP/IP
网络连接。例如用户可以在Windows
服务器下请求一台远程Linux
服务器下的MySQL
实例,如下所示:
[Lxy@VM-20-12-centos ~]$ mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 24
Server version: 5.7.41 MySQL Community Server (GPL)
Copyright (c) 2000, 2023, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
这里的客户端是Windows
,它向一台Host IP
为xxxx
的MySQL
实例发起了TCP/IP
连接请求,并且连接成功。之后就可以对MySQL
数据库进行一些数据库操作,如DDL和DML
等。
这里需要注意的是,在通过TCP/IP
连接到MySQL
实例时,MySQL
数据库会先检查一张权限视图,用来判断发起请求的客户端IP
是否允许连接到MySQL
实例。该视图在mysql
架构下,表名为user
,如下图所示:
mysql> select host,user,authentication_string from user \G
*************************** 1. row ***************************
host: localhost
user: root
authentication_string: *0C52BA2F284F417CE062039FC850F7BC1349882C
*************************** 2. row ***************************
host: localhost
user: mysql.session
authentication_string: *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE
*************************** 3. row ***************************
host: localhost
user: mysql.sys
authentication_string: *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE
3 rows in set (0.01 sec)
1.5.2命名管道和共享内存
如果两个需要进程通信的进程在一台服务器上,那么可以使用命名管道,SQl Server
数据库默认安装后的本地连接也是使用命名管道。在MySQL
数据库中须在配置文件中启用--enable-named-pipe
选择。在MySQL 4.1
之后的版本中,MySQL
还提供了共享内存的连接方式,这是通过在配置文件中添加 --shared-memory
实现的。如果想使用共享内存的方式,在连接时,MySQL
客户端还必须使用--protocol=memory
选项。
1.5.3UNIX
域套接字
在Linux
和UNIX
环境下,还可以使用UNIX
域套接字。UNIX
域套接字其实不是一个网络协议,所以只能在MySQL
客户端和数据库实例在一台服务器上的情况下使用。用户可以在配置文件中指定套接字文件的路径,如 --socket=/tmp/mysql.sock
。当数据库实例启动后,用户可以通过下列命令来进行UNIX
域套接字文件的查找:
mysql> show variables like 'socket' \G
*************************** 1. row ***************************
Variable_name: socket
Value: /var/lib/mysql/mysql.sock
1 row in set (0.00 sec)
在知道了UNIX
域套接字文件的路径后,就可以使用该方式进行连接了,如下图所示:
[Lxy@VM-20-12-centos ~]$ mysql -u root -S /var/lib/mysql/mysql.sock
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 27
Server version: 5.7.41 MySQL Community Server (GPL)
Copyright (c) 2000, 2023, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
(本章完)