在数据库领域中有两个同很容易混淆,这就是“数据库”(database)和“实例”(instance)。作为常见的数据库术语,这两个词的定义如下。
数据库:物理操作系统文件或其他形式文件类型的集合。在MySQL数据库中,数据库文件可以是frm、MYD、MYI、ibd结尾的文件。当使用NDB引擎时,数据库的文件可能不是操作系统上的文件,而是存放于内存之中的文件,但是定义仍然不变。
实例:MySQL数据库由后台线程以及一个共享内存区组成。共享内存可以被运行的后台线程所共享。需要牢记的是,数据库实例才是真正用于操作数据库文件的。
这两个同有时可以互换使用,不过两者的概念完全不同。在MySQL数据库中,实例与数据库的关通常系是一一对应的,即一个实例对应一个数据库,一个数据库对应一个实例。但是,在集群情况下可能存在一个数据库被多个数据实例使用的情况。
MySQL被设计为一个单进程多线程架构的数据库,这点与SQL Server比较类似,但与Oracle多进程的架构有所不同(Oracle的Windows版本也是单进程多线程架构的)。这也就是说,MySQL数据库实例在系统上的表现就是一个进程。
当启动实例时,MySQL数据库会去读取配置文件,根据配置文件的参数来启动数据库实例。在MySQL数据库中,可以没有配置文件,在这种情况下,MySQL会按照编译时的默认参数设置启动实例。用以下命令可以査看当MySQL数据库实例启动时,会在哪些位置査找配置文件。
mysql --help | grep my.cnf
order of preference, my.cnf, $MYSQL_TCP_PORT,
/etc/my.cnf /etc/mysql/my.cnf /usr/local/mysql/etc/my.cnf ~/.my.cnf
可以看到,My SQL 数据库是按 /etc/my.cnf -> /etc/mysql/my.cnf -> /usr/local/mysql/etc/my.cnf ->〜/.my.cnf的顺序读取配置文件的。“如果几个配置文件中都有同一个参数,MySQL数据库以哪个配置文件为准?”答案很简单,MySQL数据库会以读取到的最后一个配置文件中的参数为准。在Linux环境下,配置文件一般放在/etc/my.cnf下。配置文件中有一个参数datadin该参数指定了数据库所在的路径。在Linux操作系统下默认datadir为/usr/local/mysql/data,用户可以修改该参数,当然也可以使用该路径,不过该路径只是一个链接,具体如下:
mysql> show variables like 'datadir';
+---------------+------------------------+
| Variable_name | Value |
+---------------+------------------------+
| datadir | /usr/local/mysql/data/ |
+---------------+------------------------+
1 row in set (0.02 sec)
在MySQL环境下执行bash命令只需要在前面加一个system即可,如:
mysql> system sudo ls -lh /usr/local/mysql/data
total 388512
-rw-r----- 1 _mysql _mysql 56B 2 12 2018 auto.cnf
drwxr-x--- 151 _mysql _mysql 4.7K 9 13 14:46 hive
-rw-r----- 1 _mysql _mysql 846B 9 19 15:38 ib_buffer_pool
-rw-r----- 1 _mysql _mysql 48M 9 19 15:40 ib_logfile0
-rw-r----- 1 _mysql _mysql 48M 2 12 2018 ib_logfile1
-rw-r----- 1 _mysql _mysql 76M 9 19 15:40 ibdata1
-rw-r----- 1 _mysql _mysql 12M 9 19 15:40 ibtmp1
drwxr-x--- 77 _mysql _mysql 2.4K 2 12 2018 mysql
。。。。
数据库实例是程序,是位于用户与操作系统之间的一层数据管理软件,用户对数据库数据的任何操作,包括数据库定义、数据査询、数据维护、数据库运行控制等都是在数据库实例下进行的,应用程序只有通过数据库实例才能和数据库打交道。
这里再换一种更为直白的方式来解释:数据库是由一个个文件组成(一般来说都是二进制的文件)的,要对这些文件执行诸如SELECT、INSERT、UPDATE和DELETE之类的数据库操作是不能通过简单的操作文件来更改数据库的内容,需要通过数据库实例来完成对数据库的操作。
来看看MySQL数据库的体系结构,其结构如图所示(摘自MySQL官方手册)。
从图可以发现,MySQL由以下几部分组成:
从图还可以发现,MySQL数据库区别于其他数据库的最重要的一个特点就是其插件式的表存储引擎。MySQL插件式的存储引擎架构提供了一系列标准的管理和服务支持,这些标准与存储引擎本身无关,可能是每个数据库系统本身都必需的,如SQL分析器和优化器等,而存储引擎是底层物理结构的实现,每个存储引擎开发者可以按照自己的意愿来进行开发。
需要特别注意的是,存储引擎是基于表的,而不是数据库。
InnoDB存储引擎支持事务,其设计目标主要面向在线事务处理(OLTP)的应用。
其特点是行锁设计、支持外键,并支持类似于Oracle的非锁定读,即默认读取操作不会产生锁。从MySQL数据库5.5.8版本开始,InnoDB存储引擎是默认的存储引擎。
InnoDB存储引擎将数据放在一个逻辑的表空间中,这个表空间就像黑盒一样由InnoDB存储引擎自身进行管理。从MySQL 4.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,并以此作为主键。
MylSAM存储引擎不支持事务、表锁设计,支持全文索引,主要面向一些OLAP数据库应用。在MySQL5.5.8版本之前MylSAM存储引擎是默认的存储引擎(除Windows版本外)。数据库系统与文件系统很大的一个不同之处在于对事务的支持,然而MylSAM存储引擎是不支持事务的。究其根本,这也不是很难理解。试想用户是否在所有的应用中都需要事务呢?在数据仓库中,如果没有ETL这些操作,只是简单的报表查询是否还需要事务的支持呢?此外,MylSAM存储引擎的另一个与众不同的地方是它的缓冲池只缓存(cache)索引文件,而不缓冲数据文件,这点和大多数的数据库都非常不同。
MylSAM存储引擎表由MYD和MYI组成,MYD用来存放数据文件,MYI用来存放索引文件。可以通过使用myisampack工具来进一步压缩数据文件,因为myisampack工具使用赫夫曼(Huffman)编码静态算法来压缩数据,因此使用myisampack工具压缩后的表是只读的,当然用户也可以通过myisampack来解压数据文件。
在MySQL 5.0版本之前,MylSAM默认支持的表大小为4GB,如果需要支持大于4GB的MylSAM表时,则需要制定MAX_ROWS和AVG_ROW_LENGTH属性。从MySQL 5.0版本开始,MylSAM默认支持256TB的单表数据,这足够满足一般应用需求。
注意对于MylSAM存储引擎表,MySQL数据库只缓存其索引文件,数据文件的缓存交由操作系统本身来完成,这与其他使用LRU算法缓存数据的大部分数据库大不相同。此外,在MySQL 5.1.23版本之前,无论是在32位还是64位操作系统环境下,缓存索引的缓冲区最大只能设置为4GB。在之后的版本中,64位系统可以支持大于4GB的索引缓冲区。
NDB存储引擎是一个集群存储引擎,因此能提供更高的可用性。NDB的特点是数据全部放在内存中(从MySQL 5.1版本开始,可以将非索引数据放在磁盘上),因此主键査找(primary key lookups)的速度极快,并且通过添加NDB数据存储节点(Data Node)可以线性地提高数据库性能,是高可用、高性能的集群系统。
关于NDB存储引擎,有一个问题值得注意,那就是NDB存储引擎的连接操作(JOIN)是在MySQL数据库层完成的,而不是在存储引擎层完成的。这意味着,复杂的连接操作需要巨大的网络开销,因此査洵速度很慢。
Memory存储引擎(之前称HEAP存储引擎)将表中的数据存放在内存中,如果数据库重启或发生崩溃,表中的数据都将消失。它非常适合用于存储临时数据的临时表,以及数据仓库中的纬度表。Memory存储引擎默认使用哈希索引,而不是我们熟悉的B+树索引。
虽然Memory存储引擎速度非常快,但在使用上还是有一定的限制。比如,只支持表锁,并发性能较差,并且不支持TEXT和BLOB列类型。最重要的是,存储变长字段(varchar)时是按照定常字段(char)的方式进行的,因此会浪费内存。
此外有一点容易被忽视,MySQL数据库使用Memory存储引擎作为临时表来存放査询的中间结果集(intermediate result)。如果中间结果集大于Memory存储引擎表的容量设置,又或者中间结果含有TEXT或BLOB列类型字段,则MySQL数据库会把其转换到MylSAM存储引擎表而存放到磁盘中。之前提到MylSAM不缓存数据文件,因此这时产生的临时表的性能对于査询会有损失。
Archive 存储引擎只支持 INSERT 和 SELECT 操作,从 MySQL 5.1 开始支持索引。 Archive 存储引擎使用 zlib 算法将数据行( row )进行压缩后存储,压缩比一般可达 l : 10 。正如其名字所示, Archive 存储引擎非常适合存储归档数据,如日志信息。 Archive 存储引擎使用行锁来实现高并发的插人操作,但是其本身并不是事务安全的存储引擎,其设计目标主要是提供高速的插入和压缩功能。
Federated 存储引擎表并不存放数据,它只是指向一台远程 MySQL 数据库服务器上的表。这非常类似于 SQL Server 的链接服务器和 Oracle 的透明网关,不同的是,当前 Federated 存储引擎只支持 MySQL 数据库表,不支持异构数据库表。
Maria 存储引擎是新开发的引擎,设计目标主要是用来取代原有的 MylsAM 存储引擎,从而成为 MySQL 的默认存储引擎。 Maria 存储引擎的开发者是 MySQL 的创始人之一的 Michael widenius 。因此,它可以看做是 MyISAM 的后续版本。 Maria 存储引擎的特点是:支持缓存数据和索引文件,应用了行锁设计,提供了 MVCC 功能,支持事务和非事务安全的选项,以及更好的 BLOB 字符类型的处理性能。
Feature | InnoDB | MyISAM | MEMORY | ARCHIVE |
---|---|---|---|---|
B-tree indexes | Yes | Yes | Yes | No |
Backup/point-in-time recovery (Implemented in the server, rather than in the storage engine.) | Yes | Yes | Yes | Yes |
Cluster database support | No | No | No | No |
Clustered indexes | Yes | No | No | No |
Compressed data | Yes | Yes (Compressed MyISAM tables are supported only when using the compressed row format. Tables using the compressed row format with MyISAM are read only.) | No | Yes |
Data caches | Yes | No | N/A | No |
Encrypted data (Implemented in the server via encryption functions. Data-at-rest tablespace encryption is available in MySQL 5.7 and later.) | Yes | Yes | Yes | Yes |
Foreign key support | Yes | No | No | No |
Full-text search indexes | Yes (InnoDB support for FULLTEXT indexes is available in MySQL 5.6 and later.) | Yes | No | No |
Geospatial data type support | Yes | Yes | No | Yes |
Geospatial indexing support | Yes (InnoDB support for geospatial indexing is available in MySQL 5.7 and later.) | Yes | No | No |
Hash indexes | No (InnoDB utilizes hash indexes internally for its Adaptive Hash Index feature.) | No | Yes | No |
Index caches | Yes | Yes | N/A | No |
Locking granularity | Row | Table | Table | Row |
MVCC | Yes | No | No | No |
Replication support (Implemented in the server, rather than in the storage engine.) | Yes | Yes | Limited | Yes |
Storage limits | 64TB | 256TB | RAM | None |
T-tree indexes | No | No | No | No |
Transactions | Yes | No | No | No |
Update statistics for data dictionary | Yes | Yes | Yes | Yes |
可以通过 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.01 sec)
下面将通过 MySQL 提供的示例数据库来简单显示各存储引擎之间的不同。这里将分别运行以下语句,然后统计每次使用各存储引擎后表的大小。
mysql > CREATE TABLE mytest Engine = MyISAM AS SELECT * FROM salaries;
mysql > ALTER TABLE mytest Engine=InnoDB;
mysql > ALTER TABLE mytest Engine=ARCHIVE;
通过每次的统计,可以发现当最初表使用 MyISAM 存储引擎时,表的大小40.7MB ,使用 InnoDB 存储引擎时表增大到113.6MB ,而使用 Archive 存储引擎时表的大小却只有20.2MB 。