MySQL 8.0 20個 InnoDB 及資料字典相關的新特性

碼農談IT發表於2023-02-20

本篇將聚焦於 MySQL 8.0 InnoDB 及資料字典相關的新特性。這些新特性涉及的範圍包括:Redo log、事務排程演演算法、自增主鍵、回滾表空間、死鎖、臨時表空間、Doublewrite Buffer、資料字典、原子 DDL、information_schema、備份等。

1. Redo log 的最佳化

相關的最佳化有:

  • 對 redo log 進行了無鎖設計
  • 允許多個使用者執行緒併發寫入 redo log buffer
  • 可動態修改 innodb_log_buffer_size 的大小

2. 事務排程演演算法

當有多個事務競爭同一把鎖時,在 MySQL 8.0 之前,使用的是 FIFO(First In First Out,先進先出)演演算法,該演演算法會將鎖優先分配給最先請求的事務。

在 MySQL 8.0 中,引入了 CATS (Contention-Aware Transaction Scheduling,競爭感知事務排程)演演算法,該演演算法會計算每個事務阻塞的事務數,然後將鎖優先分配給阻塞事務最多的事務。

3. 自增主鍵的持久化

在 MySQL 8.0 之前,自增主鍵的分配是由 InnoDB 資料字典內部一個計數器來決定的。該計數器只在記憶體中維護,並不會持久化到磁碟中。

當資料庫重啟後,會基於自增主鍵的最大值(假設是 max_id)來重新初始化自增主鍵。

所以如果 max_id 之後的自增主鍵值分配但又刪除了,則資料庫重啟後,會繼續從 max_id + 1 開始分配自增主鍵值。

這就意味著,之前分配的自增主鍵值(雖然被刪除了)又被重新分配了。

當然,大多數情況下也沒有問題,不過在以下兩種場景需要注意:

  • 業務將自增主鍵作為業務主鍵。在使用的過程中可能會發現兩筆不同的訂單對應著同一個業務主鍵。

  • 歸檔場景。在歸檔的過程中有可能會出現主鍵衝突。

具體細節可參考:MySQL 8 新特性之自增主鍵的持久化

4. 預設開啟回滾表空間

在 MySQL 5.7 中,因 innodb_undo_tablespaces 預設為 0,所以回滾表空間預設是沒有開啟的。若要開啟,只能在初始化時將 innodb_undo_tablespaces 設定為非 0 值。

在 MySQL 8.0 中,innodb_undo_tablespaces 預設為 2。不僅如此,innodb_undo_tablespaces 還可線上動態修改。

從 MySQL 8.0.14 開始,支援透過 SQL 語句來管理回滾表空間。

# 新增回滾表空間,副檔名必須是.ibu。
CREATE UNDO TABLESPACE tablespace_name ADD DATAFILE 'file_name.ibu';
# 刪除回滾表空間。
DROP UNDO TABLESPACE tablespace_name;
# 在刪除回滾表空間之前,必須先將它設定為 INACTIVE 狀態。
ALTER UNDO TABLESPACE tablespace_name SET INACTIVE;
# 將回滾表空間設定為 ACTIVE 狀態。
ALTER UNDO TABLESPACE tablespace_name SET ACTIVE;

與此同時,innodb_undo_tablespaces 引數被棄用,雖然還是可以修改,但不起作用,innodb_undo_tablespaces 永遠為 2。

5. TempTable 引擎

預設的記憶體臨時表由 MEMORY 引擎更改為 TempTable 引擎,相比於前者,後者支援以變長方式儲存 VARCHAR、VARBINARY 等變長欄位。

從 MySQL 8.0.13 開始,TempTable 引擎支援 BLOB 欄位。

6. innodb_dedicated_server

引入了 innodb_dedicated_server 引數,可基於伺服器的記憶體動態設定 innodb_buffer_pool_size、innodb_redo_log_capacity 和 innodb_flush_method。

7. 關閉死鎖檢測

引入了 innodb_deadlock_detect 引數關閉死鎖檢測。

8. 線上回收臨時表空間的磁碟空間

在 MySQL 5.7 中,使用者建立的臨時表和磁碟臨時表會儲存在全域性臨時表空間(ibtmp1)中。

ibtmp1 一旦增長,就不會收縮。如果要回收 ibtmp1 的空間,就只能重啟例項。

在 MySQL 8.0 中,使用者建立的臨時表和磁碟臨時表會儲存在會話臨時表空間中。會話臨時表空間預設位於 #innodb_temp 目錄下。

一個會話最多會分配兩個臨時表空間,分別用來儲存使用者臨時表和磁碟臨時表。當會話的連線斷開時,會清空這兩個臨時表空間。

9. 設定獨立的雙寫緩衝區(Doublewrite Buffer)

在 MySQL 8.0.20 之前,雙寫緩衝區預設儲存在 InnoDB 系統表空間(ibdata1)中。

從 MySQL 8.0.20 開始,雙寫緩衝區會儲存在單獨的 #ib_16384_0.dblwr 和 #ib_16384_1.dblwr 檔案中。

從 MySQL 8.0.30 開始,innodb_doublewrite 在 ON(開啟雙寫緩衝區) 和 OFF(關閉雙寫緩衝區) 的基礎上新增了兩個選項:

  • DETECT_AND_RECOVER:作用與 ON 一樣(實際上是 ON 的同義詞)。

    在進行髒頁重新整理時,會首先將資料頁寫到雙寫緩衝區中。在進行故障恢復時,會透過雙寫緩衝區來修復資料檔案中不完整的資料頁。

  • DETECT_ONLY:也會開啟雙寫緩衝區,只不過在進行髒頁重新整理時,只會記錄資料頁的後設資料資訊,不會儲存資料頁的內容。

    所以在進行故障恢復時,即使資料檔案中存在不完整的資料頁,也不能透過雙寫緩衝區來修復。

    該選項主要是用來檢測例項啟動時是否有不完整的資料頁。

10. 禁用重做日誌記錄(redo logging)

在 MySQL 8.0.21 開始,可以使用 ALTER INSTANCE DISABLE INNODB REDO_LOG 命令禁用重做日誌記錄。

該特性適用於資料載入場景,線上生產環境切記不要禁用。

禁用後,可透過 ALTER INSTANCE ENABLE INNODB REDO_LOG 命令開啟。

11. 檢視錶快取在 Buffer Pool 中資料頁的數量

可透過 information_schema.innodb_cached_indexes 檢視錶快取在 Buffer Pool 中資料頁的數量。

SELECT 
  tables.name, indexes.name, cached.n_cached_pages
FROM
  information_schema.innodb_cached_indexes AS cached,
  information_schema.innodb_indexes AS indexes,
  information_schema.innodb_tables AS tables
WHERE
  cached.index_id = indexes.index_id AND indexes.table_id = tables.table_id;
+------------+------------+----------------+
| table_name | index_name | n_cached_pages |
+------------+------------+----------------+
| db1/t1     | idx_c1     |            279 |
| db1/t1     | PRIMARY    |           4756 |
+------------+------------+----------------+
2 rows in set (0.00 sec) 

12. 動態調整 redo log 的容量

從 MySQL 8.0.30 開始,可透過 innodb_redo_log_capacity 引數來動態調整 redo log 的容量。

在 MySQL 8.0.30 之前,InnoDB 預設會在資料目錄下建立兩個 redo log。Redo log 的數量和大小分別由 innodb_log_files_in_group 和 innodb_log_file_size 決定。

隨著 innodb_redo_log_capacity 的引入,InnoDB 會在資料目錄的 #innodb_redo 目錄下建立 32 個 redo log。Redo log 的總大小由 innodb_redo_log_capacity 決定。

innodb_redo_log_capacity 如果沒有顯式設定,則預設等於 innodb_log_file_size * innodb_log_files_in_group。

13. 基於 InnoDB 的資料字典

引入了原生的、基於 InnoDB 的資料字典。這些資料字典表位於 mysql 庫中,對使用者不可見。

如果是 debug 版本,可透過以下方式訪問資料字典表。

mysql> SET SESSION debug='+d,skip_dd_table_access_check';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT name, schema_id, hidden, type FROM mysql.tables WHERE schema_id=1 AND hidden='System';
+------------------------------+-----------+--------+------------+
| name                         | schema_id | hidden | type       |
+------------------------------+-----------+--------+------------+
| catalogs                     |         1 | System | BASE TABLE |
| character_sets               |         1 | System | BASE TABLE |
| check_constraints            |         1 | System | BASE TABLE |
| collations                   |         1 | System | BASE TABLE |
...
+------------------------------+-----------+--------+------------+
32 rows in set (0.02 sec)

在 MySQL 8.0 中,mysql 庫中的 InnoDB 表(包括資料字典表)會儲存在資料目錄下的 mysql.ibd 檔案中,而其它非 InnoDB 表則依舊儲存在 mysql 目錄下。

[root@mysql data]# ls mysql
general_log_213.sdi  general_log.CSM  general_log.CSV  slow_log_214.sdi  slow_log.CSM  slow_log.CSV

14. 移除了 frm 等檔案

移除了之前版本的 frm、par、TRN、TRG、isl、db.opt、ddl_log.log 等檔案,這些檔案會儲存部分後設資料資訊。

15. 不再識別手動建立的資料庫目錄

因為資料字典的引入,MySQL 不再識別手動建立的資料庫目錄。

看下面這個示例。

在 MySQL 5.7 例項的資料目錄下建立一個目錄,該目錄會被 MySQL 識別。

# cd /data/mysql/3307/data/
# mkdir test

mysql5.7> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| test               |
+--------------------+
5 rows in set (0.00 sec)

mysql5.7USE test
Database changed
mysql5.7SHOW TABLES;
Empty set (0.00 sec)

相同的操作如果是在 MySQL 8.0 中執行,則不會識別。

16. 原子 DDL

在 MySQL 8.0 之前,後設資料資訊會儲存在多個檔案中。在進行 DDL 的過程中,如果例項異常重啟,可能會導致這些檔案中的後設資料資訊不一致,甚至產生 Orphan(孤兒)表。

MySQL 8.0 引入了原子 DDL,可將 DDL 操作相關的後設資料更新、儲存引擎操作和 binlog 寫入放到一個原子操作中。

這樣就能保證 DDL 操作要麼提交,要麼回滾,不存在任何中間狀態,即使 DDL 期間例項發生了重啟。

除此之外,一些 DDL 操作的行為也發生了變化,看下面這個示例。

# MySQL 5.7
mysql5.7> CREATE TABLE t1(id INT);
Query OK, 0 rows affected (0.02 sec)

# 雖然命令報錯了,但 t1 表還是被刪除了
mysql5.7> DROP TABLE t1,t2;
ERROR 1051 (42S02): Unknown table 'slowtech.t2'

mysql5.7> SHOW TABLES;
Empty set (0.00 sec)

# MySQL 8.0
mysql8.0CREATE TABLE t1(id INT);
Query OK, 0 rows affected (0.03 sec)

# 命令報錯,t1 表沒被刪除
mysql8.0> DROP TABLE t1,t2;
ERROR 1051 (42S02): Unknown table 'slowtech.t2'

mysql8.0> SHOW TABLES;
+--------------------+
| Tables_in_slowtech |
+--------------------+
| t1                 |
+--------------------+
1 row in set (0.00 sec)

17. SDI

資料庫物件的後設資料資訊除了儲存在資料字典中,也會再儲存一份 SDI(Serialized Dictionary Information,序列化的字典資訊)。

當資料字典不可用時,我們可以基於 SDI 提取物件的後設資料資訊。

對於 InnoDB 表,SDI 會儲存在 .ibd 檔案中,需透過 ibd2sdi 命令檢視。

對於其它儲存引擎的表,SDI 會儲存在 .sdi 檔案中,可直接透過 cat 命令檢視。

18. information_schema 查詢效能提升

information_schema 中的部分表已重構為基於資料字典的檢視,在此之前,這些表是透過臨時表來實現的。

information_schema.statistics 和 information_schema.tables 兩張表中表相關的統計資訊會快取起來以提升查詢效能。

快取的時間由 information_schema_stats_expiry 引數決定,預設是 86400 秒(24小時)。

如果要更新某張表的統計資訊,可執行 ANALYZE TABLE 操作。

19. information_schema 表中的列名會以大寫形式返回

查詢時,在沒有指定別名的情況下,返回的列名會與查詢指定的列名一致,包括大小寫也一樣。

看下面這個示例。

mysql> SELECT id FROM test.t1;
+----+
| id |
+----+
|  1 |
+----+
1 row in set (0.00 sec)

mysql> SELECT Id FROM test.t1;
+----+
| Id |
+----+
|  1 |
+----+
1 row in set (0.00 sec)

在 MySQL 8.0 中,如果查詢的是 information_schema 中的表,則列名會以大寫形式返回。

# 無論查詢使用的是 table_name 還是 Table_Name,返回的列名都是 TABLE_NAME。 
mysql8.0> SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'users';
+------------+
| TABLE_NAME |
+------------+
| users      |
+------------+
1 row in set (0.00 sec)

mysql8.0SELECT Table_Name FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'users';
+------------+
| TABLE_NAME |
+------------+
| users      |
+------------+
1 row in set (0.00 sec)

20. 備份

在 MySQL 8.0 之前,在使用 mysqldump 或 mysqlpump 進行全庫備份(--all-databases)時,即使沒有指定 --routines 和 --events,也會備份儲存過程(包括自定義函式)和定時器。

之所以會這樣,是因為這兩類物件的定義資訊是儲存在 mysql.proc 和 mysql.event 表中。當進行全庫備份時,會備份 mysql 庫中的所有表,自然也包括 mysql.proc 和 mysql.event。

在 MySQL 8.0 中,沒有 mysql.proc 和 mysql.event 表,取而代之的是 mysql.routines 和 mysql.events。注意,替換後的表是資料字典表,對使用者是不可見的。

所以,在 MySQL 8.0 中,如果要備份儲存過程和定時器,需顯式指定 --routines 和 --events。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024924/viewspace-2935957/,如需轉載,請註明出處,否則將追究法律責任。

相關文章