MySQL(四)--------表類型(存儲引擎)的選擇

一、MySQL存儲引擎簡介

       MySQL支持多種存儲引擎,以適用於不同領域的數據庫應用需要,用戶可以根據需要進行選擇甚至是定製自己的引擎以提高應用效率。

        使用如下命令查看當前版本mysql支持的存儲引擎:

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)

       在使用MySQL創建新表的時候,如果沒有指定存儲引擎,那麼系統會使用默認的存儲引擎,MySQL5.5之前的默認存儲引擎是MyISAM,之後改成了InnoDB。使用如下命令查看當前默認存儲引擎:

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, 1 warning (0.00 sec)

       在創建新表的時候如果不想用默認的存儲引擎,可以使用關鍵字ENGINE顯示的指定存儲引擎類型,下面ai表的存儲引擎定義爲MyISAM,country表的引擎定義爲InnoDB:

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.01 sec)

mysql> create table country (country_id smallint unsigned not null auto_increment,country 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.02 sec)

         如果對於一個已經存在的表想要更改它的存儲引擎,可以使用alter語句:

mysql> alter table ai engine=innodb;
Query OK, 0 rows affected (0.03 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.1 MyISAM

      MyISAM不支持事務和外鍵,其優勢是訪問速度快,所以對事務完整性沒有要求或者以SELECT、INSERT爲主的應用基本上可以用這個引擎來創建表。

       每個MyISAM類型的表在磁盤上都會存儲爲3個文件,文件名都和表名一樣,擴展名分別爲:

  •    .frm  (存儲表定義)
  •    .MYD (MYData,存儲數據)
  •    .MYI(MYIndex,存儲索引)

數據文件和索引文件可以放置在不同的目錄,平均分佈IO,獲得更快的速度;如果需要指定具體的目錄,在創建表的時候可以通過 DATA DIRECTORY 和 INDEX DIRECTORY 語句指定,但是需要注意,路徑必須是絕對路徑且具有訪問權限。

       MyISAM類型的表可能會損壞,造成的原因很多,損壞後會造成以下情況:表可能無法訪問;提示你需要修復;訪問後返回錯誤的結果;數據庫異常重新啓動等等。這時候我們就需要對錶進行修復,CHECK TABLE 語句來檢測MyISAM表的健康狀況,REPAIR TABLE 語句來修復。(具體修復過程及查找損壞原因後面再介紹)

        MyISAM表的3種不同存儲格式,分別是:

  • 靜態表(固定長度);
  • 動態表;
  • 壓縮表;

關於這些表的具體介紹就不多說明,這跟數據結構裏面的一些存儲規則很類似,這裏僅僅說一下需要注意的一些點:

 1. 在靜態表中查詢數據會在返回之前將後面的空格刪除:

mysql> create table myisam_char(name char(10)) engine=myisam;
Query OK, 0 rows affected (0.01 sec)

mysql> insert into myisam_char values('abcde'),('abcde  '),('  abcde'),('  abcde  ');
Query OK, 4 rows affected (0.00 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 |            7 |
+---------+--------------+
4 rows in set (0.00 sec)

從上面的例子可以看出MyISAM類型的靜態表在存儲的時候會按照指定的列的寬度來向後補足空格,但是在應用訪問的時候會返回去掉後面空格的數據,因此在存儲的數據前後有空格時需要注意,數據後面的空格會被一併抹除掉,前面的空格則會保留。

  2. 頻繁的更新和刪除動態表的記錄會產生碎片,因此需要定期執行OPTIMIZE TABLE 語句或 myisamchr -r 命令來改善性能。

  3. 壓縮表由 myisampack 工具創建。

   2.2 InnoDB

    InnoDB是MySQL裏面默認的存儲引擎,也是使用的最多的存儲引擎;它提供了具有提交、回滾和崩潰恢復能力的事務安全性能,但相對於MyISAM存儲引擎,InnoDB寫的處理效率差一些,而且會佔用更多的磁盤空間以保留數據和索引。

    1. 自增長列

     InnoDB表的自增長列可以手動插入,如果忽略或是插入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.02 sec)

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

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

自增長列的起始值默認從1開始,如果想要從別的值開始可以用語句 ALTER TABLE *** AUTO_INCREMENT = n 來指定,但是需要注意,該語句強制指定的初始值是保存在內存中的,一旦數據庫重新啓動就需要重新設置

        可以使用LAST_INSERT_ID()來查詢當前線程最後插入記錄使用的值:

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

mysql> select LAST_INSERT_ID();   這裏需要解釋以下爲什麼這裏查出來的記錄是2,因爲這個查詢只會查到上一次的insert或update語句更改的最新記錄,但是它需要是自動增長的纔算,手動指定的不算,比如這裏手動指定的記錄4就不算,而上面手動指定的0或null被自動增長代替,所以算作自增,因此此處結果爲2.
+------------------+
| LAST_INSERT_ID() |
+------------------+
|                2 |
+------------------+
1 row in set (0.00 sec)

mysql> insert into autoincre_demo(name) values('5'),('6'),('7');  這裏沒有指定自增長列,它是自己增長的,因而查詢結果爲當前多條數據的第一條自增長列對應的值,也就是5。
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

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

下面幾個例子就很好的證明了上面的結論
mysql> insert into autoincre_demo values(8,'8');
Query OK, 1 row affected (0.01 sec)

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

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

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

mysql> insert into autoincre_demo(name) values('10');
Query OK, 1 row affected (0.01 sec)

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

這裏必須提一點,對於InnoDB表,自增長列必須是索引,且排在第一列,如果是作爲組合索引,它也必須組合索引的第一列。但是對於MyISAM表就不必,它的自增長列可以是組合索引的其他列,此時的自增就會先按照第一索引進行排序後再自增,如下面的例子:

mysql> create table autoincre_demo2(d1 smallint not null auto_increment,d2 smallint not null,name varchar(10),index(d2,d1))engine=myisam;
Query OK, 0 rows affected (0.01 sec)

mysql> insert into autoincre_demo2(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_demo2;
+----+----+------+
| 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)

    2. 外鍵約束

     MySQL中只有InnoDB支持外鍵,在創建外鍵時要求父表必須要有對應的索引。下面創建一個country表作爲父表,city表作爲子表,country_id作爲外鍵:

由於country表之前創建過,這裏就顯示一下它的結構
mysql> show create table country \G;
*************************** 1. row ***************************
       Table: country
Create Table: CREATE TABLE `country` (
  `country_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
  `country` 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
1 row in set (0.00 sec)

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),key idx_fk_country_id (country_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.03 sec)

        關鍵字RESTRICT和NO ACTION相同,作用是拒絕父表的的更新刪除操作(如果子表有關聯記錄的情況下);CASCADE表示父表在更新或刪除時,同時對子表對應的記錄進行同樣操作;SET NULL則表示父表在更新或刪除操作時,子表的對應字段被置爲空。後兩種要謹慎使用,因爲會導致數據丟失。

       因爲外鍵的存在導致表之間聯繫比較緊密,在導入表數據或者修改表結構時往往由於這種聯繫導致速度較慢,此時我們可以暫時關閉外鍵的檢查來加快處理速度,關閉的命令爲:SET FOREIGN_KEY_CHECKS = 0;執行完之後通過命令:SET CHECK_FOREIGN_KEY = 1 ;改回原來的狀態。

       對InnoDB類型的表,通過使用show table status命令來顯示包含外鍵的表的狀態信息:

mysql> show table status like 'city' \G;
*************************** 1. row ***************************
           Name: city
         Engine: InnoDB
        Version: 10
     Row_format: Dynamic
           Rows: 0
 Avg_row_length: 0
    Data_length: 16384
Max_data_length: 0
   Index_length: 16384
      Data_free: 0
 Auto_increment: 1
    Create_time: 2018-12-17 16:07:17
    Update_time: NULL
     Check_time: NULL
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options:
        Comment:
1 row in set (0.00 sec)

    3. 存儲方式

     InnoDB存儲表和索引主要有兩種方式:

  • 使用共享表空間存儲,數據和索引保存在innodb_data_home_dir和innodb_data_file_path定義的表空間中,可以是多個文件。
  • 使用多表空間存儲,每個表的數據和索引單獨保存在.ibd中。如果是分區表,則每個分區對應單獨的.ibd文件,文件名時“表名+分區名”,可以在創建分區的時候指定每個分區的數據文件的位置,以此將表的IO均勻的分佈在多個磁盤上。

       一般都使用的共享表存儲,如果要使用多表空間存儲需要設置參數 innodb_file_per_table,並且需要重啓服務後纔可以對新建的表生效,但原來的表仍使用共享表空間存儲;

       多表空間的數據文件沒有大小限制,不需要設置初始大小等一些其它限制參數;

       使用多表空間特性的表,可以方便的進行單表備份和恢復操作,但不能直接複製.ibd文件,因爲還有一些東西在共享表空間裏,可以通過以下命令“  ALTER TABLE tb1_name DISCARD TABLESPACE;  ALTER TABLE tb1_name IMPORT TABLESPACE;" 進行備份和恢復,但是隻能恢復到原來所在的數據庫中,如果想要恢復到別的數據庫需要通過mysqldump和mysqlimport來實現。

注意:即使在多表空間的存儲方式下,共享表空間仍然是必須的,因爲InnoDB把內部數據詞典和在線重做日誌放在這個文件中。

      2.3 MEMORY

         MEMORY存儲引擎使用內存中的內容來創建表,每個MEMORY表只實際對應一個磁盤文件,格式是.frm。它的訪問速度很快,默認採用hash索引,但一旦服務關閉,表中的數據就會丟失。

         下面使用city表的記錄來創建memory的表,並且指定索引爲hash索引還是btree索引:

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.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> create index men_hash using hash on tab_memory (city_id);
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show index from tab_memory \G;
*************************** 1. row ***************************
        Table: tab_memory
   Non_unique: 1
     Key_name: men_hash
 Seq_in_index: 1
  Column_name: city_id
    Collation: NULL
  Cardinality: 0
     Sub_part: NULL
       Packed: NULL
         Null:
   Index_type: HASH
      Comment:
Index_comment:
1 row in set (0.00 sec)

如果想把hash索引更換爲btree索引,需這樣做:

mysql> drop index men_hash on tab_memory;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> create index men_hash using btree on tab_memory(city_id);
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

         如何將memory類型表的數據保存下來?我們在啓動MySQL時需要使用--init-file選項,把把各種表單數據操作語句放入到文件中,這樣就可以在在服務啓動時從持久穩固的數據源裝載表。

        memory表存儲數據的大小受到max_heap_table_size系統變量的約束,初始值爲16MB,當然,我們可以根據需要加大,並且在創建memory表時可以通過MAX_ROWS字句指定表的最大行數來限制表的大小。

        當memory表不再用的時候需要釋放它的內存,應當執行DELETE FROM 或TRUNCATE TABLE 或 DROP TABLE操作。

        memory類型的表主要用於那些內容變化不頻繁的代碼表,或者作爲統計的中間結果表;對這種表進行更新操作需要謹慎,應考慮到數據的持久性問題。

    2.4 MERGE

     

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章