1. 程式人生 > >《MySQL 8.0 參考手冊》第 14 章 MySQL 資料字典

《MySQL 8.0 參考手冊》第 14 章 MySQL 資料字典

文章目錄

原文地址:MySQL 8.0 Reference Manual

MySQL 8.0 使用一個事務型的資料字典儲存資料庫物件的相關資訊。在之前的 MySQL 版本中,字典資料儲存在元資料檔案、非事務型的表以及儲存引擎相關的資料字典中。

本章介紹新資料字典的主要特性、優勢、用法差異以及侷限性。關於資料字典帶來的其他影響,可以參考 MySQL 8.0 版本說明中的 “資料字典” 部分。

新的資料字典具有以下優勢:

重要
使用資料字典的伺服器與沒有使用資料字典的伺服器存在一些使用上的差異; 參見 第 14.7 節,“資料字典用法差異”。另外,升級到 MySQL 8.0 的過程與之前版本的升級存在一些不同之處,在升級之前需要執行某些檢查,確認升級條件已經就緒。更多相關資訊,可以參考, see

第 2.11.1 節,“升級 MySQL”,特別是 第 2.11.1.4 節, “升級前的準備”

14.1 資料字典模式

資料字典表是受系統保護的,使用者只有在 MySQL 除錯版本中才能直接訪問資料字典。不過,MySQL 支援通過 INFORMATION_SCHEMA 表和 SHOW 語句檢視資料字典表中的資料。如果想要檢視資料字典中包含哪些表,可以參考 資料字典表

MySQL 8.0 中仍然存在系統表,並且可以通過在 mysql 系統資料庫上執行 SHOW TABLES 語句進行檢視。通常來說,MySQL 系統表與數字字典表的區別在於系統表儲存的是一些輔助資訊,例如時區和幫助資訊;而資料字典表包含了執行 SQL 查詢所需的資訊。兩者在升級方面也存在區別。升級 MySQL 系統表需要執行 mysql_upgrade 程式。資料字典的升級由 MySQL 伺服器進行管理,參考下文。

資料字典升級過程

新版本的 MySQL 可能包含了資料字典表的修改。新安裝的 MySQL 已經包含了這些變更,但是如果使用新的 MySQL 二進位制檔案進行就地升級,使用新版本的 MySQL 啟動服務時應用這些變更。在伺服器啟動時,會將伺服器的資料字典版本與資料字典中儲存的版本資訊進行比較,決定是否需要升級資料字典表。如果需要並且系統支援升級,伺服器將會建立新的資料字典表,將儲存的元資料複製到新的表中,使用新表替換舊錶(原子性操作),並且重新初始化資料字典。如果不需要進行升級,伺服器繼續啟動而不會升級資料字典表。

資料字典表的升級是一個原子操作,意味著所有的資料字典表都會成功升級,或者整個操作都會失敗。如果升級失敗,伺服器啟動時將會出錯。此時,可以使用舊的二進位制檔案和舊的資料目錄啟動伺服器。如果再次使用新的二進位制檔案啟動伺服器時,將會再次嘗試資料字典的升級。

通常來說,成功升級資料字典表之後,無法再使用舊的二進位制檔案啟動伺服器。因此,資料字典表升級之後不支援 MySQL 伺服器的降級。

可以使用 mysqld --no-dd-upgrade 選項阻止伺服器啟動時升級資料字典表。如果指定了 --no-dd-upgrade,當伺服器發現它的資料字典版本與儲存在資料字典表中版本不一致時,伺服器將會啟動失敗,並且顯示一個數據字典升級被禁止的錯誤。

使用 MySQL 除錯版本檢視資料字典表

預設情況下,資料字典表受系統保護,無法直接進行訪問;但是如果使用支援除錯的選項(使用 CMake 的 -DWITH_DEBUG=1 選項),並且指定 +d,skip_dd_table_access_check 除錯選項和修飾符編譯 MySQL,就可以訪問資料字典表。關於除錯版本的編譯,可以參考 第 29.5.1.1 節, “MySQL 除錯版本編譯”

警告
不推薦直接對資料字典表進行修改或者插入,可能會導致 MySQL 例項無法使用。

在使用除錯選項編譯 MySQL 之後,使用以下 SET 語句設定 mysql 客戶端會話對於資料字典表的可見性:

mysql> SET SESSION debug='+d,skip_dd_table_access_check';

使用以下查詢返回資料字典表的列表:

mysql> SELECT name, schema_id, hidden, type FROM mysql.tables where schema_id=1 AND hidden='System';

使用 SHOW CREATE TABLE 檢視資料字典表的定義。例如:

mysql> SHOW CREATE TABLE mysql.catalogs\G

14.2 刪除基於檔案的元資料

在之前的 MySQL 版本中,某些字典資料儲存在元資料檔案中。這種儲存方法存在一些問題,包括訪問時需要執行高成本的檔案掃描,容易受到系統錯誤的影響,難以進行復制和故障時的恢復,同時缺少可擴充套件性,很難為新的特性和關係物件增加元資料。
MySQL 8.0 刪除了以下元資料檔案。除非另有說明,之前儲存在元資料檔案中的資料現在儲存在資料字典表中。

  • .frm 檔案:表的元資料檔案。隨著 .frm 檔案的刪除,還帶來了以下變化:
    • 刪除了使用 .frm 檔案時對於 64KB 表定義大小的限制。
    • INFORMATION_SCHEMA.TABLES 中的 VERSION 欄位的值被硬編碼成 10,表示最後在 MySQL 5.7 中使用的.frm 檔案版本。
  • .par 檔案:分割槽定義檔案。InnoDB 不再使用 MySQL 5.7 中的分割槽定義檔案,而是使用 InnoDB 表的原生分割槽支援。
  • .TRN 檔案:觸發器名稱空間檔案。
  • .TRG 檔案:觸發器引數檔案。
  • .isl 檔案:InnoDB 符號連結檔案,它儲存了在資料目錄之外建立的表空間檔案(file-per-table)的位置。
  • db.opt 檔案:資料庫配置檔案。這些檔案(每個資料庫目錄一個檔案)包含了資料庫的預設字符集。

14.3 事務型資料字典

資料字典模式使用事務型(InnoDB)的表儲存字典資料。資料字典表和非資料字典資訊的系統表都位於 mysql 資料庫中。

資料字典表使用單個 InnoDB 表空間進行統一儲存,即 mysql.ibd,該檔案位於 MySQL 資料目錄中。mysql.ibd 檔案必須位於 MySQL 資料目錄中,並且不能修改該檔案的名稱,也不能被其他表空間使用。

字典資料與其他 InnoDB 表中的資料一樣受到事務保護,包括提交、回滾和故障恢復。

14.4 資料字典快取

資料字典快取是一個全域性的共享快取區,用於快取訪問過的資料字典物件,以減少磁碟 I/O。與 MySQL 中的其他快取機制一樣,資料字典物件快取使用一個基於 LRU 的刪除策略,從記憶體中刪除最近最少使用的物件。

資料字典快取分為不同的快取分割槽,用於快取不同的物件型別。某些快取分割槽的大小限制可以配置,而另一些快取分割槽的大小是固定不變的(硬編碼)。

  • 表空間定義快取分割槽:快取表空間的定義。tablespace_definition_cache 選項用於設定能夠快取的表空間定義物件的數量。預設值為 256。

  • 模式定義快取分割槽:快取模式的定義。schema_definition_cache 選項用於設定能夠快取的模式定義物件的數量。預設值為 256。

  • 表定義快取分割槽:快取表的定義。能夠快取的表定義物件的數量等於 max_connections 的大小,預設值為 151。

    除了表定義快取分割槽之外,還存在一個表定義快取區,它使用 table_definition_cache 選項進行設定。兩個快取區都快取了表的定義,但是用於不同的 MySQL 伺服器元件。兩個快取中的物件之間沒有依賴關係。

  • 儲存程式定義快取分割槽:快取儲存程式的定義。stored_program_definition_cache 選項用於設定能夠快取的儲存程式定義物件的數量。預設值為 256。

    除了儲存程式定義快取分割槽之外,還存在一個儲存過程和儲存函式的快取區,它使用 stored_program_cache 選項進行配置。

    stored_program_cache 選項用於設定每個連線快取的儲存過程或函式的“軟”上限,每次執行儲存過程或函式時都會檢查該上限。而另一方面,儲存程式定義快取分割槽是為其他用途快取儲存過程定義物件的一個共享快取。儲存程式定義快取分割槽中的物件與儲存過程快取或儲存函式快取中的物件之間沒有依賴關係。

  • 字符集定義快取分區:快取字符集的定義,最多能夠快取 256 個定義物件。

  • 排序規則定義快取分割槽:快取排序規則的定義,最多能夠快取 256 個定義物件。

關於資料字典物件快取配置選項的可選值,參考 第 5.1.8 節,“伺服器系統變數”

14.5 INFORMATION_SCHEMA 與資料字典整合

隨著新的資料字典的引入,以下 INFORMATION_SCHEMA 中的表被修改為基於資料字典表的檢視:

  • CHARACTER_SETS
  • COLLATIONS
  • COLLATION_CHARACTER_SET_APPLICABILITY
  • COLUMNS
  • COLUMN_STATISTICS
  • EVENTS
  • FILES
  • INNODB_COLUMNS
  • INNODB_DATAFILES
  • INNODB_FIELDS
  • INNODB_FOREIGN
  • INNODB_FOREIGN_COLS
  • INNODB_INDEXES
  • INNODB_TABLES
  • INNODB_TABLESPACES
  • INNODB_TABLESPACES_BRIEF
  • INNODB_TABLESTATS
  • KEY_COLUMN_USAGE
  • KEYWORDS
  • PARAMETERS
  • PARTITIONS
  • REFERENTIAL_CONSTRAINTS
  • RESOURCE_GROUPS
  • ROUTINES
  • SCHEMATA
  • STATISTICS
  • ST_GEOMETRY_COLUMNS
  • ST_SPATIAL_REFERENCE_SYSTEMS
  • TABLES
  • TABLE_CONSTRAINTS
  • TRIGGERS
  • VIEWS
  • VIEW_ROUTINE_USAGE
  • VIEW_TABLE_USAGE

現在,針對這些表的查詢語句將會更加高效,因為它們通過資料字典表獲取資訊,而不是其他的更慢的方式。尤其是那些基於資料字典表的實現的 INFORMATION_SCHEMA 視圖表:

  • 伺服器不再需要為每個查詢的 INFORMATION_SCHEMA 表建立一個臨時表。
  • 對於之前需要執行目錄掃描(例如,列舉資料庫名稱或資料庫中的表名)或者讀取檔案(例如,從 .frm 檔案中讀取資訊)訪問的底層資料字典表資訊,現在查詢 INFORMATION_SCHEMA 表時使用表查詢的方式獲取資料。(除此之外,即使是非檢視的 INFORMATION_SCHEMA 表,例如資料庫名稱和表名這樣的值也是從資料字典中返回,而不需要掃描目錄或檔案。)
  • 優化器可以利用底層資料字典表上的索引構建高效的查詢計劃,而之前使用臨時表的方式不會利用索引。

這些改進同樣適用於 SHOW 語句,它顯示了 INFORMATION_SCHEMA 視圖表中的相應資訊。例如,SHOW DATABASES 顯示了 SCHEMATA 表中的資訊。

除了引入資料字典表上的檢視之外,還對 STATISTICS 和 TABLES 表中的統計資訊進行了快取,提高了 INFORMATION_SCHEMA 的查詢效能。系統變數 information_schema_stats_expiry 定義了表統計資訊快取的過期時間。預設值為 86400 秒(24 小時)。如果不存在統計資訊快取或快取過期,查詢直接從儲存引擎返回統計資訊。可以隨時使用 ANALYZE TABLE 語句更新表統計資訊的快取。

將 information_schema_stats_expiry 設定為 0 可以在查詢 INFORMATION_SCHEMA 時直接從儲存引擎返回最新的統計資訊,但是從快取中返回統計資訊更快。

更多資訊,參考 第 8.2.3 節,“INFORMATION_SCHEMA 查詢優化”

14.6 序列化資料字典資訊(SDI)

除了在資料字典中儲存了關於資料庫物件的元資料之外,MySQL 還儲存一份序列化的元資料。這些資料被稱為序列化字典資訊(Serialized Dictionary Information)。 InnoDB 儲存引擎在它的表空間檔案中儲存 SDI 資料。其他儲存引擎在模式目錄下的相應 .sdi 檔案中儲存 SDI 資料。 SDI 資料使用壓縮的 JSON 格式進行儲存。

對於所有的 InnoDB 表空間檔案,除了臨時表空間和撤銷表空間檔案,都儲存了序列化資料字典資訊(SDI)。每個 InnoDB 表空間檔案中的 SDI 記錄只包含了該表空間中的表和表空間物件的描述。

InnoDB 表空間檔案中的 SDI 資訊只能通過相應表上的 DDL 操作進行更新。

SDI 資料為元資料提供了冗餘的資訊。例如,如果資料字典不可用,可以使用 ibd2sdi 工具直接從 InnoDB 表空間檔案中提取物件的元資料資訊。

對於 InnoDB,一條 SDI 記錄需要一個索引頁,預設大小為 16KB。不過,SDI 資料進行了壓縮,以減少儲存需求。

對於由多個表空間組成的 InnoDB 分割槽表,SDI 資料儲存在第一個分割槽的表空間檔案中。

MySQL 伺服器在 DDL 操作的過程中,使用內部的 API 建立和維護 SDI 記錄。

IMPORT TABLE 語句基於 .sdi 檔案中的資訊執行 MyISAM 表的匯入。更多資訊可以參見 第 13.2.5 節,“IMPORT TABLE 語法”

14.7 資料字典用法差異

使用資料字典的 MySQL 伺服器與沒有使用資料字典的伺服器存在一些使用上的區別:

  • 在之前的版本中,啟用 innodb_read_only 系統變數只會禁止 InnoDB 表的建立和刪除。從 MySQL 8.0 開始,啟用 innodb_read_only 將會禁止所有儲存引擎表的建立和刪除。任何儲存引擎表的建立和刪除都會修改 mysql 系統資料中的資料,而這些資料表使用 InnoDB 儲存引擎,不能被修改(啟用了 innodb_read_only)。任何需要修改資料字典表的其他操作也會受到同樣的限制。例如:

  • 無法執行 ANALYZE TABLE 語句,因為它會更新資料字典中關於表的統計資訊。

  • 無法執行 ALTER TABLE tbl_name ENGINE=engine_name 語句,因為它會更新資料字典中的表的儲存引擎資訊。

    注意
    啟用 innodb_read_only 也會對 mysql 系統資料庫中的非字資料字典表產生重要影響。詳細資訊可以參考第 15.13 節, “InnoDB 啟動選項與系統變數” 中關於 innodb_read_only 的介紹。

  • 在之前的版本中,mysql 系統資料庫中的表可以使用 DML 和 DDL 語句直接進行操作。從 MySQL 8.0 開始,資料字典表被設定為不可見,不能直接進行查詢和修改。不過,大部分的表都存在一個對應的 INFORMATION_SCHEMA 表,可以針對這些表進行查詢。這種方式的好處在於,隨著新版本的開發,底層的資料字典表可以不斷進行修改,而INFORMATION_SCHEMA 中的介面可以保持不變,不會影響到應用程式的使用。

  • MySQL 8.0 中的 INFORMATION_SCHEMA 表的實現與資料字典密切相關,導致了一些使用上的區別:

    • 在之前的版本中,查詢 INFORMATION_SCHEMA 中的 STATISTICSTABLES 中關於表的統計資訊時,直接從相關的儲存引擎返回資料。從 MySQL 8.0 開始,預設使用快取的表統計資訊。系統變數 information_schema_stats_expiry 定義了快取表統計資訊的過期時間。預設時間為 86400 秒(24小時)。(使用 ANALYZE TABLE 語句可以隨時更新表的快取統計資訊。)只有當快取統計資訊不存在或者過期時,查詢才會從儲存引擎返回統計資訊。要想總是從儲存引擎返回最新的統計資訊,可以將 information_schema_stats_expiry 設定為 0 。更多資訊可以參考 第 8.2.3 節, “優化 INFORMATION_SCHEMA 查詢”

    • 某些 INFORMATION_SCHEMA 表是基於資料字典表的檢視,優化器查詢時可以利用這些底層表上的索引。因此,查詢 INFORMATION_SCHEMA 資訊時返回結果的順序可能不確定,這個取決於優化器的選擇。如果想要返回指定順序的結果,可以加上 ORDER BY 子句。

    • mysqldumpmysqlpump 不再備份 INFORMATION_SCHEMA 資料庫,即使在命令列中明確指定匯出該資料庫。

    • CREATE TABLE dst_tbl LIKE src_tbl 要求 src_tbl 必須是一個基表,如果它是 INFORMATION_SCHEMA 中基於資料字典表的檢視時,該語句無法執行。

    • 在之前的版本中,查詢 INFORMATION_SCHEMA 表時返回的列標題使用查詢語句中的大小寫形式。以下查詢返回的標題為 table_name:

      SELECT table_name FROM INFORMATION_SCHEMA.TABLES;
      

      從 MySQL 8.0 開始,返回大寫的列標題;上面的查詢返回的標題為TABLE_NAME。如果需要,可以通過列別名的方式返回指定的大小寫形式。例如:

      SELECT table_name AS 'table_name' FROM INFORMATION_SCHEMA.TABLES;
      
  • 資料字典對 mysqldumpmysqlpump 匯出 mysql 系統資料庫的影響如下:

    • 在之前的版本中,可以匯出 mysql 系統資料庫中的任何表。從 MySQL 8.0 開始,mysqldump 和 mysqlpump 只能匯出其中的非資料字典表。
    • 在之前的版本中,使用 –all-databases 選項匯出所有資料庫表時,不需要新增 –routines–events 選項也會匯出儲存程式和事件:匯出結果中包含了 mysql 系統資料庫,因此也就包含了 proc 表和 event 表中的儲存程式和事件的定義。從 MySQL 8.0 開始,不再使用 event 表和 proc 表。相應的物件儲存在資料字典表中,但是這些表不會被匯出。想要在使用 --all-databases 匯出時包含儲存程式和事件,需要明確指定 --routines 和 --events 選項。
    • 在之前的版本中,使用 --routines 選項需要擁有 proc 表的 SELECT 許可權。從 MySQL 8.0 開始,不再使用 proc 表;使用 --routines 選項需要全域性的 SELECT 許可權。
    • 在之前的版本中,通過匯出 proc 表和 event 表,可以在匯出儲存程式和事件定義的同時,匯出它們的建立時間戳和修改時間戳。從 MySQL 8.0 開始,不再使用這些表, 因此無法匯出這些時間戳。
  • 在之前的版本中,建立儲存程式時,如果使用了非法的字元,將會產生一個警告資訊。從 MySQL 8.0 開始,使用非法字元將會產生一個錯誤資訊。

14.8 資料字典侷限性

MySQL 資料字典目前還存在一些臨時的侷限性:

  • 不支援在資料目錄下手動(例如,使用 mkdir 命令)建立資料庫目錄。MySQL 伺服器不會識別手動建立的資料庫目錄。
  • DDL 操作需要佔用更長的時間,因為它需要寫入儲存、回滾日誌以及重做日誌,而不僅僅是之前的 .frm 檔案。

人生本來短暫,你又何必匆匆!點個贊再走吧!