关于 MariaDB 系列其他文章的传送门

一、常见开源数据库的发行分支¶
MySQL:
- 社区版本:
5.5,5.6,5.7,8.0; - 存储引擎使用 InnoDB,不过 InnoDB 也被 ORACLE 收购了;
- Innobackup 是 MySQL 的备份工具,收费昂贵。
Percona-Server:
- 存储引擎使用 XtraDB,是 Percona 公司研发的 InnoDB 的增强版,并且全面兼容 InnoDB;
- Xtrabackup 是开源的备份工具,打击了 Innobackup;
- percona-tools: 开源的数据库的工具包。
MariaDB:
- MySQL 的分支,版本:
5.5对应 MySQL 的5.5,而 MariaDB 没有所谓的5.6,而是直接将后面的定位到10.X; - 存储引擎默认使用 XtraDB,在 CentOS 7 自带的 YUM 源中的 MariaDB 就使用此引擎。使用
SHOW ENGINES;查看存储引擎时显示的虽然是 InnoDB,但是描述里有写实际是 XtraDB,因为完全兼容,所以引擎名称为 InnoDB。但是实际上我们使用的是 Percona 公司的 XtraDB 存储引擎。

本文主要介绍 MariaDB
二、MariaDB 的安装¶
MariaDB 5.5 被收录在 Base 仓库,使用 yum 可直接安装。
1 | yum install mariadb-server -y |
注意事项:
- MariaDB 是单进程多线程。
- 第一次运行时后使用
mysql_secure_installation执行安全初始化。 - 数据文件保存在
/var/lib/mysql下,每个数据库对应一个目录。 - 使用客户端工具连接本地数据库时使用
mysql -uroot -hlocalhost,也可直接执行mysql默认效果是一样的。
三、存储引擎介绍¶
存储引擎也称为“表类型”,表级别概念,不建议在同一个库中的表上使用不同的 ENGINE;
SHOW ENGINES; 列出存储引擎的信息。
1 | MariaDB [(none)]> show engines; |
本文介绍两个存储引擎:
- InnoDB
- MyISAM
1. InnoDB¶

InnoDB 是 InnoBase 公司参考 ORACLE 模型开发的数据库存储引擎,后被 ORACLE 收购。
现在是 MySQL 和 MariaDB 的默认存储引擎。
特点是支持事务,行级锁和外键约束,InnoDB 是 事务型存储引擎,适合对事务要求较高的场景,比如在线交易系统的电商,较适用于处理大量短期事务;而冗长的事务并不适合 InnoDB 和 MariaDB,或许需要使用 ORACLE 或 PgSQL 吧。
InnoDB 的数据是存储于 表空间 (table space) 当中的,表空间有以下两种工作方式:
innodb_file_per_table=OFF:所有数据库中的所有类型为 InnoDB 的表的数据和索引,都存储于同一个共享表空间中;一个表空间对应于磁盘上一个或多个串行的文件,该文件是一个黑盒,初始位于/var/lib/mysql/ibdata1;innodb_file_per_table=ON:每表的数据文件(数据和索引,存储于数据库目录)存储于自己专用的表空间文件中,并存储于数据库目录下;同样支持一个表空间对应于磁盘上一个或多个串行的文件;
InnoDB 支持多版本并发控制 MVCC (Mutli Version Concurrency Control);
- 支持高并发;
- 支持四个隔离级别,默认级别为 REPEATABLE-READ;
- 锁的颗粒度:支持 行级锁 和 间隙锁,防止幻读;
支持使用 聚集索引,默认构建在主键索引上。聚集索引就是数据和索引保存在一起,找到数据即找到索引,而非聚集索引在找到索引后还需要依靠指针,再额外加载数据所在的磁盘块,才能加载数据。
支持 B 树索引和 Hash 索引:
- B 树索引:也叫平衡树,特性是所有文件路径的层级深度一致。相反,Linux 中各文件的目录深度就各不相同。
- 自适应 Hash 索引:就是把数据通过 Hash 计算后放在 Hash 桶中,当查询时,计算出查询数据的 Hash 值,当做查询条件,和 Hash 桶内的数据做命中查询。
总结:
- 数据存储:表空间;
- 并发:MVCC,间隙锁,行级锁;
- 索引:聚集索引、辅助索引;
- 性能:预读操作、内存数据缓冲、内存索引缓存、自适应Hash索引、插入操作缓存区;
- 备份:支持热备;
2. MyISAM¶
MyISAM 存储引擎支持全文索引(FULLTEXT index)、数据压缩、空间函数(GIS)索引。
- 不支持事务、外键。
- 锁的颗粒度为:表级锁。
- 如果数据库发生崩溃无法保证表安全恢复,MyISAM 的衍生版 Aria 支持崩溃后表的安全恢复。
特性:
- 加锁和并发:表级锁;
- 修复:手动或自动修复、但可能会丢失数据;
- 索引:非聚集索引;
- 延迟索引更新;
- 表压缩;
数据文件:每个表有三个文件,存储于数据库目录中:
tbl_name.frm:表格式定义;tbl_name.MYD:数据文件;tbl_name.MYI:索引文件。
适用场景:只读或读多写少的场景、较小的表(以保证崩溃后恢复的时间较短)。
其它的存储引擎¶
MariaDB 自带的可切换的其他引擎:
| 数据引擎名 | 介绍 |
|---|---|
| CSV | 将 CSV 文件(以逗号分隔字段的文本文件)作为 MySQL 表文件。 |
| MRG_MYISAM | 将多个 MyISAM 表合并成的虚拟表。 |
| BLACKHOLE | 类似于 /dev/null,不真正存储数据。 |
| MEMORY | 内存存储引擎,支持 hash 索引,表级锁,常用于临时表。 |
| FEDERATED | 用于访问其它远程 MySQL 服务器上表的存储引擎接口。 |
MariaDB 额外还支持很多种存储引擎,只不过没有自带:
- OQGraph
- SphinxSE
- TokuDB
- Cassandra
- CONNECT
- SQUENCE
五、InnoDB 的相关配置¶
数据库配置参数¶
数据库配置参数分为:
-
用户可自行修改的会话级变量;
- 支持运行时修改参数,立即生效,仅对当前会话有效;
- 需要重启后才能生效的配置;
-
只有管理员才能修改的全局变量;
- 支持运行时修改的参数,立即生效,改变后只对新会话有效;
- 需要重启后才能生效的配置;
查看数据库参数:
SHOW [SESSION | GLOBAL] VARIABLES;:查看服务器配置参数;SHOW [SESSION | GLOBAL] VARIABLES LIKE 'innodb%';:查看指定的服务器配置参数;
定义数据库配置参数:
SET [SESSION | GLOBAL] <VAR=ON|OFF>;:改变服务器配置参数。
示例:
1 | SET GLOBAL innodb_file_per_table=ON; |
查看 InnoDB 内部的各种状态信息:
SHOW ENGINE INNODB STATUS;
状态计数器。显示级别分为当前会话和全局,不加 SESSION 则默认显示当前会话级别:
SHOW [SESSION | GLOBAL] STATUS;
InnoDB 的并发控制¶
实现并发机制的相关概念¶
每个请求通过长连接或短连接的方式连接到 MariaDB 的连接器,MariaDB 会生成一个线程来维持这个连接。
SHOW PROCESSLIST;:可以显示所有线程。
当有多个线程同时访问一个数据集时,就要为这个数据施加一种机制,基于 MVCC(多版本并发控制),通过锁机制和事务隔离,保证数据的一致性。
1. 锁 Lock¶
锁类型:
为了最大化数据库事务的并发能力,数据库中的锁被设计为两种模式,分别是 共享锁 和 互斥锁。当一个事务获得共享锁之后,它只可以进行读操作,所以共享锁也叫读锁;而当一个事务获得一行数据的互斥锁时,就可以对该行数据进行读和写操作,所以互斥锁也叫写锁。
- 读锁:共享锁,可被多个读操作共享;
- 写锁:排它锁,独占锁。
锁粒度:
- 表锁:在表级别施加锁,并发性较低;
- 行锁:在行级别施加锁,并发性较高;维持锁状态的成本较大。
锁策略:在锁粒度及数据安全性之间寻求一种平衡机制;
- 存储引擎级别:级别以及何时施加或释放锁由存储引擎自行决定;
- MariaDB 级别:用户可自行决定,也允许显式请求。
锁类别:
- 显式锁:用户手动请求的锁;
- 隐式锁:存储引擎自行根据需要施加的锁;
显式锁的使用¶
显示锁可以由用户手动设定。
- 锁定表:
LOCK TABLES tbl_name read|write, tbl_name read|write, ... - 解锁表:
UNLOCK TABLES;
这个命令是全局读锁定,执行了命令之后所有库所有表都被锁定只读。
- 锁定:
FLUSH TABLES tbl_name,... [《 WITH READ LOCK]; - 解锁:
UNLOCK TABLES;
2. 事务¶
什么是事务?¶
所谓事务,就是一组原子性的 SQL 查询、或者是一个或多个 SQL 语句组成的独立工作单元;
- 多个步骤的 SQL 语句的执行状态必须一致,要么都执行,要么都不执行。
- 每句 SQL 执行前的内容和执行后的内容全部被保存在撤销日志中,如果执行不下去或者宕机后,就从日志读取执行前的数据并回滚整个事务;如果执行顺利完成,则会将日志中执行后的数据同步到表中。
- 事务日志文件的大小是固定的,可以设置,所以应该有至少一组两个,这样当一个写满后会使用另一个继续写,然后将满了的日志文件中的已执行数据同步至表中,保留执行前的数据,以释放空间。
Innodb 的事务日志是指 Redo log,简称 Log,默认保存在日志文件 /var/lib/mysql/ib_logfile* 里面。
Innodb 还有另外一个日志 Undo log,但 Undo log 是存放在共享表空间里面的(ibdata* 文件,存储的是 check point 日志序列号)。
定义事务日志相关参数:
innodb_log_files_in_group:一组日志文件需要几个文件,至少两个;innodb_log_group_home_dir:日志存放在哪,默认在数据目录下;innodb_log_file_size:每个日志文件的大小,单位字节,默认5MB;innodb_mirrored_log_groups:定义有几个日志组。innodb_flush_logs_at_trx_commit:每当有事务提交时,如何将缓冲区的事务日志同步至磁盘中,以保证事务的安全性。0:每一秒,将 log buffer(内存)同步一次至 log file(事务日志);且同时将 log file 同步到 data file(数据文件);1:每次提交时,将 log buffer 同步至 log file,且同时将 log file 同步到 data file;偏安全性高;2:每次提交时,将 log buffer 同步至 log file,但不会将 log file 同步到 data file;偏性能好;- 建议关闭 autocommit,而后将此值设置为 1 或 2。
事务隔离级别,隔离效果由低到高:
| 隔离级别 | 脏读 | 不可重复读 | 幻读 | 描述 |
|---|---|---|---|---|
| READ-UNCOMMITTED 未提交也可读 | ✅ | ✅ | ✅ | 读取到未提交的数据 |
| READ-COMMITTED 提交后才可读 | ❌ | ✅ | ✅ | 读已经提交的数据,ORACLE 默认隔离级别 |
| REPEATABLE-READ 可重复读 | ❌ | ❌ | ✅ | 可以重复读,MySQL 的默认隔离级别。 |
| SERIALIZABLE 串行化 | ❌ | ❌ | ❌ | 可串行化。事务间完全隔离,事务不能并发,只能串行执行 |
| ✅: 可能出现 ❌: 不会出现 |
定义隔离级别¶
1 | mysql> SET @@session.tx_isolation=REPEATABLE-READ; |
如何判定一个存储引擎支持事务,需要通过 ACID 测试:
- AUTOMICITY:原子性,整个事务中的所有操作要么全部成功执行,要么全部失败后回滚;
- CONSISTENCY:一致性,数据库总是应该从一个一致性状态转为另一个一致性状态;
- ISOLATION:隔离性,一个事务所做出的操作在提交之前,是否能被其它事务可见;出于保证并发操作之目的,隔离有多种级别;
- DURABILITY:持久性,事务一旦提交,其所做出的修改会永久保存;
手动控制事务¶
启动事务
1 | START TRANSACTION; SQL; SQL; |
提交事务
1 | COMMIT; |
回滚事务
1 | ROLLBACK; |
事务也支持锚点(savepoints),可选择回滚至指定锚点:
SAVEPOINT <identifier>:定义锚点;ROLLBACK [WORK] TO [SAVEPOINT] <identifier>:回滚至某个锚点;RELEASE SAVEPOINT <identifier>:清除某个锚点。
关于自动提交单语句事务¶
MariaDB 默认开启单语句事务,即每句 SQL 为一个单独的事务,这对性能可能会产生影响。
查询当前是否开启,1 为开启,0 为关闭:
1 | MariaDB [(none)]> SELECT @@session.autocommit; |
关闭单语句事务:SET @@session.autocommit=0,仅当前会话生效。
四、日志¶
数据库的日志分为:
- 查询日志:general_log
- 慢查询日志:log_slow_queries
- 错误日志:log_error,log_warnings
- 二进制日志:binlog
- 中继日志:relay_log
- 事务日志:innodb_log
1. 查询日志¶
记录查询的语句,信息量会很大,一般不开启。
日志可用存储位置:
- 文件:FILE
- 表:TABLE (mysql.general_log, mysql.slow_log)
配置:
general_log={ON|OFF}:启用查询日志;general_log_file=HOSTNAME.log:指定日志 file 的保存路径;log_output={FILE|TABLE|NONE}:定义日志存储位置,可使用分隔符,来指定多个。
2. 慢查询日志¶
运行时间超出指定时长的查询日志。
SELECT @@long_query_time;:查询当前定义的超时时间,默认 10 秒:。
日志可用存储位置:
- 文件:FILE
- 表:TABLE(mysql.slow_log)
配置:
log_slow_queries={ON|OFF}:定义慢查询是否开启,建议在配置文件中配置;slow_query_log={ON|OFF}:同上,版本不同语法可能不同;slow_query_log_file=:指定日志 file 的保存路径;log_output={FILE|TABLE|NONE}:定义日志存储位置,可用,指定多个;log_slow_filter=admin,filesort,filesort_on_disk,full_join,full_scan,query_cache,query_cache_miss,tmp_table,tmp_table_on_disk:定义记录哪些类型的慢查询操作;log_slow_rate_limit:定义记录日志的速率限制;log_slow_verbosity:定义日志记录的详细程度。
3. 错误日志¶
除了记录错误日志,还记录以下几种信息:
- mysqld 启动和关闭过程 输出的信息;
- mysqld 运行中产生的错误信息;
- event scheduler 运行时产生的信息;
- 主从复制架构中,从服务器复制线程启动时产生的日志;
配置:
log_error=/var/log/mariadb/mariadb.log|OFF:指定了文件即开启日志,否则使用OFF关闭。log_warnings={ON|OFF}:是否记录警告信息。
4. 二进制日志¶
用于记录引起数据改变或存在引起数据改变的潜在可能性的语句(STATEMENT)或改变后的结果(ROW),也可能是二者混合。
主要的功能用来“重放”。
二进制日志有三种格式:
定义方法:binlog_format={STATEMENT|ROW|MIXED}。
STATEMENT: 记录 SQl 语句;ROW: 直接记录 SQL 语句执行的结果,而不是 SQL 本身;MIXED: 混合,让数据库自行判断使用哪一种。
启用二进制日志¶
log_bin=/PATH/TO/BIN_LOG_FILE:指定二进制日志保存位置,指定了文件即表示开启,否则使用 OFF 关闭,切记文件不要加.log后缀。此参数是全局只读变量,不支持运行时修改,可以写在配置文件/etc/my.cnf的[mysqld]中;二进制日志按序号滚动生成,会自动创建*.index的文本文件,记录了当前日志的文件序号。SET session.sql_log_bin={ON|OFF}:控制某个会话中的“写”操作语句是否会被记录于日志文件中;
查看二进制日志的相关命令¶
SHOW MASTER|BINARY LOGS;:查看二进制日志文件列表,每次重启 mariadb 会滚动一个新日志;SHOW MASTER STATUS;:查看当前正在使用的二进制日志文件是哪个;SHOW BINLOG EVENTS [IN 'log_name'] [FROM pos] [LIMIT [offset,] row_count]:查看二进制日志文件中都记录了哪些事件:[FROM pos]:指定从哪个字节位置开始显示;[LIMIT [offset,]:指定显示几个事件,offset使用整数;
示例:
1 | MariaDB [(none)]> SHOW BINLOG EVENTS IN 'master_log.000002' FROM 245 LIMIT 2; |
显示结果中的字段代表了:
Pos:此事件在二进制日志中的起始字节位置;End_log_pos:此事件在二进制日志中的结束字节位置;
一些配置和命令¶
max_binlog_size=1073741824:自定义多少字节会滚动一次;sync_binlog=N:当每进行 N 次事务提交之后,MariaDB 将进行一次 fsync 之类的磁盘同步指令来将binlog_cache中的数据强制写入磁盘。默认的设置是 0,这时候的性能是最好的,但是风险也是最大的。设置为 0 和设置为 1 的系统写入性能差距可能高达 5 倍甚至更多。所以很多 MySQL DBA 设置的并不是使用最安全的 1,而是 100 或者是 0,这样牺牲一定的一致性,可以获得更高的并发和性能。FLUSH LOGS;:把内存中的日志同步到磁盘上,二进制文件会滚动一次;
在 shell 直接查看二进制日志文件的工具¶
mysqlbinlog:--start-datetime=:从指定的时间开始查看,格式"YYYY-MM-DD hh:mm:ss";--stop-datetime=:指定结束的时间;-j, --start-position=#:从指定的字节位置查看;--stop-position=#:指定结束的字节位置;--user, --host, --password:查看其它服务器的二进制日志。
二进制日志的显示格式及解释:
1 | ## at 553 |
# at 553:事件的起始字节位置;#160831 9:56:08:事件发生的日期时间;id:server id 1:事件发生的服务器;end_log_pos 624:事件的结束位置;Query:事件的类型;ID:thread_id=2:事件发生时所在服务器执行此事件的线程的;exec_time=0:语句的时间戳与将其写入二进制日志文件中的时间差;error_code=0:错误代码;SET TIMESTAMP=1472608568/*!*/;:事件内容。
5. 中继日志¶
从服务器上记录下来从主服务器的二进制日志文件同步过来的事件,一般用于主从复制。
6. 事务日志¶
事务型存储引擎 InnoDB 用于保证事务特性的日志文件,上文已经介绍过,就不重复了。
扩展阅读:
《 浅谈数据库并发控制 - 锁和 MVCC 》
《 数据库事务隔离级别 – 脏读、幻读、不可重复读(清晰解释)》
