1. 程式人生 > >【MySQL技術內幕】01-MySQL體系結構和儲存引擎

【MySQL技術內幕】01-MySQL體系結構和儲存引擎

1、定義資料庫和例項

在資料庫領域中有兩個同很容易混淆,這就是“資料庫”(database)和“例項”(instance)。作為常見的資料庫術語,這兩個詞的定義如下。

資料庫:物理作業系統檔案或其他形式檔案型別的集合。在MySQL資料庫中,資料庫檔案可以是ftm、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
。。。。

2、MySQL體系結構

資料庫例項是程式,是位於使用者與作業系統之間的一層資料管理軟體,使用者對資料庫資料的任何操作,包括資料庫定義、資料査詢、資料維護、資料庫執行控制等都是在資料庫例項下進行的,應用程式只有通過資料庫例項才能和資料庫打交道。

這裡再換一種更為直白的方式來解釋:資料庫是由一個個檔案組成(一般來說都是二進位制的檔案)的,要對這些檔案執行諸如SELECT、INSERT、UPDATE和DELETE之類的資料庫操作是不能通過簡單的操作檔案來更改資料庫的內容,需要通過資料庫例項來完成對資料庫的操作。

來看看MySQL資料庫的體系結構,其結構如圖所示(摘自MySQL官方手冊)。

從圖可以發現,MySQL由以下幾部分組成:

  • 連線池元件
  • 管理服務和工具元件
  •  SQL介面元件
  • 査詢分析器元件
  • 優化器元件
  • 緩衝(Cache)元件
  • 外掛式儲存引擎
  • 物理檔案

從圖還可以發現,MySQL資料庫區別於其他資料庫的最重要的一個特點就是其外掛式的表儲存引擎。MySQL外掛式的儲存引擎架構提供了一系列標準的管理和服務支援,這些標準與儲存引擎本身無關,可能是每個資料庫系統本身都必需的,如SQL分析器和優化器等,而儲存引擎是底層物理結構的實現,每個儲存引擎開發者可以按照自己的意願來進行開發。

需要特別注意的是,儲存引擎是基於表的,而不是資料庫。

3、MySQL儲存引擎

3.1、InnoDB儲存引擎

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,並以此作為主鍵。

3.2、MylSAM儲存引擎

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的索引緩衝區。

3.3、NDB儲存引擎

NDB儲存引擎是一個叢集儲存引擎,因此能提供更高的可用性。NDB的特點是資料全部放在記憶體中(從MySQL 5.1版本開始,可以將非索引資料放在磁碟上),因此主鍵査找(primary key lookups)的速度極快,並且通過新增NDB資料儲存節點(Data Node)可以線性地提高資料庫效能,是高可用、高效能的集群系統。

關於NDB儲存引擎,有一個問題值得注意,那就是NDB儲存引擎的連線操作(JOIN)是在MySQL資料庫層完成的,而不是在儲存引擎層完成的。這意味著,複雜的連線操作需要巨大的網路開銷,因此査洵速度很慢。

3.4、Memory儲存引擎

Memory儲存引擎(之前稱HEAP儲存引擎)將表中的資料存放在記憶體中,如果資料庫重啟或發生崩潰,表中的資料都將消失。它非常適合用於儲存臨時資料的臨時表,以及資料倉庫中的緯度表。Memory儲存引擎預設使用雜湊索引,而不是我們熟悉的B+樹索引。

雖然Memory儲存引擎速度非常快,但在使用上還是有一定的限制。比如,只支援表鎖,併發效能較差,並且不支援TEXT和BLOB列型別。最重要的是,儲存變長欄位(varchar)時是按照定常欄位(char)的方式進行的,因此會浪費記憶體。

此外有一點容易被忽視,MySQL資料庫使用Memory儲存引擎作為臨時表來存放査詢的中間結果集(intermediate result)。如果中間結果集大於Memory儲存引擎表的容量設定,又或者中間結果含有TEXT或BLOB列型別欄位,則MySQL資料庫會把其轉換到MylSAM儲存引擎表而存放到磁碟中。之前提到MylSAM不快取資料檔案,因此這時產生的臨時表的效能對於査詢會有損失。

3.5、Archive 儲存引擎

Archive 儲存引擎只支援 INSERT 和 SELECT 操作,從 MySQL 5.1 開始支援索引。 Archive 儲存引擎使用 zlib 演算法將資料行( row )進行壓縮後儲存,壓縮比一般可達 l : 10 。正如其名字所示, Archive 儲存引擎非常適合儲存歸檔資料,如日誌資訊。 Archive 儲存引擎使用行鎖來實現高併發的插人操作,但是其本身並不是事務安全的儲存引擎,其設計目標主要是提供高速的插入和壓縮功能。

3.6、Federated 儲存引擎

Federated 儲存引擎表並不存放資料,它只是指向一臺遠端 MySQL 資料庫伺服器上的表。這非常類似於 SQL Server 的連結伺服器和 Oracle 的透明閘道器,不同的是,當前 Federated 儲存引擎只支援 MySQL 資料庫表,不支援異構資料庫表。

3.7、Maria 儲存引擎

Maria 儲存引擎是新開發的引擎,設計目標主要是用來取代原有的 MylsAM 儲存引擎,從而成為 MySQL 的預設儲存引擎。 Maria 儲存引擎的開發者是 MySQL 的創始人之一的 Michael widenius 。因此,它可以看做是 MyISAM 的後續版本。 Maria 儲存引擎的特點是:支援快取資料和索引檔案,應用了行鎖設計,提供了 MVCC 功能,支援事務和非事務安全的選項,以及更好的 BLOB 字元型別的處理效能。

4、各儲存引擎之間的比較

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 。