MySQL基础学习笔记之——表类型(存储引擎)的选择

表类型(存储引擎)的选择

1、MySQL 存储引擎概述

插件式存储引擎是 MySQL 数据库最重要的特性之一,用户可以根据应用的需要选择如何存储和索引数据、是否使用事务等。MySQL 默认支持多种存储引擎,以适应与不同的领域的数据库应用需要。

MySQL 5.x 支持的存储引擎包括 MyISAM、InnoDB、BDB、MEMORY、MERGE、EXAMPLE、NDB Cluster、ARCHIVE、CSV、BLACKHOLE、FEDERATED 等,其中 InnoDB 和 BDB 提供事务安全表

创建表时如果不指定存储引擎,那么系统就会使用默认存储引擎,MySQL 的默认引擎是 InnoDB。如果要修改默认的存储引擎,可以在参数文件中设置 default_storage_engine。查看当前的默认存储引擎,可以使用下面的命令:

mysql> show variables like '%storage_engine%';
+----------------------------------+--------+
| Variable_name                    | Value  |
+----------------------------------+--------+
| default_storage_engine           | InnoDB |
| default_tmp_storage_engine       | InnoDB |
| disabled_storage_engines         |        |
| internal_tmp_disk_storage_engine | InnoDB |
+----------------------------------+--------+
4 rows in set (0.00 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
...

在创建表的时候,可以通过增加 ENGINE 关键字设置新建表的存储引擎,例如:

mysql> create table ai(
    -> i bigint(20) NOT NULL AUTO_INCREMENT,
    -> PRIMARY KEY(i)
    -> )ENGINE = MyISAM DEFAULT charset = gbk;
Query OK, 0 rows affected (0.00 sec)
mysql> create table country(
    -> country_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
    -> conutry VARCHAR(50) NOT NULL,
    -> last_update TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    -> PRIMARY KEY(country_id)
    -> )ENGINE=InnoDB DEFAULT charset=gbk;
Query OK, 0 rows affected (0.01 sec)

可以使用 alter table 将一个已经存在的表修改成其他的存储引擎:

mysql> alter table ai engine = innodb;
Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show create table ai \G
*************************** 1. row ***************************
       Table: ai
Create Table: CREATE TABLE `ai` (
  `i` bigint(20) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`i`)
) ENGINE=InnoDB DEFAULT CHARSET=gbk
1 row in set (0.00 sec)

2、各种存储引擎的特性

特点 MyISAM InnoDB MEMORY MEGRE NDB
存储限制 64TB 没有
事务安全 支持
锁机制 表锁 行锁 表锁 表锁 行锁
B 树索引 支持 支持 支持 支持 支持
哈希索引 支持 支持
全文索引 支持
集群索引 支持
索引缓存 支持 支持 支持 支持 支持
数据可压缩 支持
空间使用 N/A
内存使用 中等
批量插入的速度
支持外键 支持

2.1、MyISAM

MyISAM 不支持事务、也不支持外键,其优势是访问的速度快,对事务完整性没有要求或者以 SELECT、INSERT 为主的应用基本上都可以使用这个引擎来创建表

每个 MyISAM 在磁盘上存储成 3 个文件,其文件名都和表名相同,但是扩展名分别是:

  • .frm(存储表定义);
  • .MYD(MYData,存储数据);
  • .MYI(MYIndex,存储索引)。

数据文件和索引文件可以放在不同的目录,平均分布 I/O,获得更快的速度。

要指定索引文件和数据文件的路径,需要在创建表的时候通过 DATA DIRECTORY 和 INDEX DIRECTORY 语句指定。

MyISAM 类型的表可能会损坏,原因有很多种,损坏后的表可能不能被访问,会提示需要修复或者访问后返回错误的结果。MyISAM 类型的表提供修复的工具,可以用 CHECK TABLE 语句来检查 MyISAM 表的健康,并用 REPAIRE TABLE 语句来修复一个损坏的表

MyISAM 的表还支持 3 中不同的存储格式:

  • 静态(固定长度)表;
  • 动态表;
  • 压缩表。

其中,静态表是默认存储格式。静态表中的字段都是非变长字段,这样每个记录都是固定长度的,这种存储方式的优点是存储非常快,容易缓存,出现故障容易恢复;缺点是占用的空间通常比动态表多。静态表的数据在存储时会按照列的宽度定义补足空格,但是在应用访问的时候并不会得到这些空格,这些空格在返回给应用之前已经去掉。

mysql> create table Myisam_char(name char(10))engine=MyISAM;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into Myisam_char values('abcde'),('abcde  '),('  abcde'),(' abcde ');
Query OK, 4 rows affected (0.01 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> select name,length(name) from Myisam_char;
+---------+--------------+
| name    | length(name) |
+---------+--------------+
| abcde   |            5 |
| abcde   |            5 |
|   abcde |            7 |
|  abcde  |            6 |
+---------+--------------+
4 rows in set (0.00 sec)

有上面的例子可知,插入记录后面的空格都被去掉了,前面的空格保留了

动态表中包含变长的字段,记录不是固定的长度,这样存储的优点是占用的空间较少,但是频繁地更新和删除记录会产生碎片,需要定期执行 OPTIMIZE TABLE 语句或 myisamchk -r 命令来改善性能,并且在出现故障时恢复相对比较困难

压缩表由 myisampack 工具创建,占据非常小的磁盘空间

2.2、InnoDB

InnoDB 存储引擎提供了具有提交、回滚和崩溃恢复能力的事务安全。但是对比 MyISAM 的存储引擎,InnoDB 写的处理效率会差一些,并且会占用更多的磁盘空间以保留数据和索引。

下面重点介绍存储引擎 InnoDB 的表在使用过程中不同于使用其他存储引擎的表的特点:

2.2.1、自动增长列

自动增长的列,可以手动插入值,但插入 0 或为空时,实际插入的将是自动增长的值

mysql> create table autoincre_demo(
    -> i smallint not null auto_increment,
    -> name varchar(10),primary key(i)
    -> )engine = innodb;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into autoincre_demo values(1,"1"),(0,'2'),(null,'3'),(5,'4'),(0,'5');
Query OK, 5 rows affected (0.00 sec)
Records: 5  Duplicates: 0  Warnings: 0

mysql> select * from autoincre_demo;
+---+------+
| i | name |
+---+------+
| 1 | 1    |
| 2 | 2    |
| 3 | 3    |
| 5 | 4    |
| 6 | 5    |
+---+------+
5 rows in set (0.00 sec)

可以通过 “alter table 表名 auto_increment=n;” 语句强制设置自动增长列的初始值,默认从 1 开始,但是该初始值是保留在内存中,如果该值在使用之前数据库重启,那么这个强制的默认值就会丢失。

可以使用 last_insert_id() 查询当前线程最后插入记录使用的值。如果一次插入了多条记录,那么返回的是第一条记录使用的自动增长值。

mysql> insert into autoincre_demo values(7,"7");
Query OK, 1 row affected (0.00 sec)

mysql> select LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
|                2 |
+------------------+
1 row in set (0.00 sec)

mysql> insert into autoincre_demo(name) values('8'),('9');
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> select LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
|                8 |
+------------------+
1 row in set (0.00 sec)

对于 InnoDB 表,自动增长列必须是索引如果是组合索引,也必须是组合索引的第一列。但是对于 MyISAM 表,自动增长列也可以是组合索引的其他列,这样插入数据后,自动增长列是按照组合索引的前面几列进行排序后递增的。例如:

mysql> create table autoincre_myisam(
    -> d1 smallint not null auto_increment,
    -> d2 smallint not null,
    -> name varchar(10),
    -> index(d2,d1)		#自动增长列作为了组合索引的第二列
    -> )engine = myisam;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into autoincre_myisam(d2,name) values(2,'2'),(3,'3'),(4,'4'),(2,'2'),(3,'3'),(4,'4');
Query OK, 6 rows affected (0.00 sec)
Records: 6  Duplicates: 0  Warnings: 0

mysql> select * from autoincre_myisam;
+----+----+------+
| d1 | d2 | name |
+----+----+------+
|  1 |  2 | 2    |
|  1 |  3 | 3    |
|  1 |  4 | 4    |
|  2 |  2 | 2    |
|  2 |  3 | 3    |
|  2 |  4 | 4    |
+----+----+------+
6 rows in set (0.00 sec)
mysql> create table autoincre_innodb(
    -> d1 smallint not null auto_increment,
    -> d2 smallint not null,
    -> name varchar(10),
    -> index(d2,d1)
    -> )engine = innodb;
ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key		#提示自动增长列必须是组合索引的第一列

2.2.2、外键约束

MySQL 支持外键的存储引起只有 InnoDB,在创建外键的时候,要求父表必须有对应的索引,子表在创建外键的时候也会自动创建对应的索引。

下面的例子:数据库中有两个表,country 是父表,country_id 为主键索引,city 为子表,country_id 字段为外键,对应于 country 表的主键 country_id。

mysql> create table city(
    -> city_id smallint unsigned not null auto_increment,
    -> city varchar(50) not null,
    -> country_id smallint unsigned not null,
    -> last_update timestamp not null default current_timestamp on update current_timestamp,
    -> primary key(city_id),
    -> foreign key (country_id) references country (country_id) on delete restrict on update cascade
    -> )engine=InnoDB default charset=utf8;
Query OK, 0 rows affected (0.00 sec)

在创建索引时,可以指定在删除、更新父表时,对子表进行的相应操作,包括 RESTRICT、CASCADE、SET NULL、NO ACTION。其中 Restrict 和 NO ACTION 相同,是指限制在子表有关联记录的情况下父表不能更新;CASCADE 表示父表在更新或删除时,更新或者删除自表对应的记录;SET NULL 则表示父表在更新或删除时,子表的对应字段被 SET NULL。

2.2.3、存储方式

InnoDB 存储表和索引表有以下两种存储方式:

  • 使用共享表空间存储,这种方式创建的表的表结构保存在 .frm 文件中,数据和索引保存在 innodb_data_home_dir 和 innodb_data_file_path 定义的表空间中,可以是多个文件。
  • 使用多表空间存储,这种方式创建的表的表结构仍然保存在 .frm 文件中,但是每个表的数据和索引单独保存在 .idb 中。如果是个分区表,则每个分区对应单独的 .idb 文件,文件名是 “表名+分区名”,可以在创建分区的时候指定每个分区的数据文件的位置,以此来将表的 IO 均匀分布在多个磁盘上。

2.3、MEMORY

MEMORY 存储引擎使用存在于内存中的内容来创建表。每个 MEMORY 表只实际对应一个磁盘文件,格式为 .frm。MEMORY 类型的表访问非常的快,因为它的数据是放在内存中的,并且默认使用 HASH 索引,但是一旦服务关闭,表中的数据就会丢失。

mysql> create table tab_memory engine = memory
    -> select city_id ,city,country_id
    -> from city group by city_id;
Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> select count(*) from tab_memory;
+----------+
| count(*) |
+----------+
|        0 |
+----------+
1 row in set (0.00 sec)

mysql> show table status like 'tab_memory' \G
*************************** 1. row ***************************
           Name: tab_memory
         Engine: MEMORY
        Version: 10
     Row_format: Fixed
           Rows: 0
 Avg_row_length: 155
    Data_length: 0
Max_data_length: 16252835
   Index_length: 0
      Data_free: 0
 Auto_increment: NULL
    Create_time: 2020-08-19 08:24:33
    Update_time: NULL
     Check_time: NULL
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options:
        Comment:
1 row in set (0.00 sec)

猜你喜欢

转载自blog.csdn.net/qq_36879493/article/details/108092169