亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

MySQL 8.0數(shù)據(jù)字典的初始化與啟動流程

 更新時間:2024年06月25日 09:01:46   作者:華為云開發(fā)者聯(lián)盟  
數(shù)據(jù)字典(Data Dictionary, DD)用來存儲數(shù)據(jù)庫內(nèi)部對象的信息,這些信息也被稱為元數(shù)據(jù)(Metadata),包括schema名稱、表結(jié)構(gòu)、存儲過程的定義等,本文主要介紹MySQL 8.0數(shù)據(jù)字典的基本概念和數(shù)據(jù)字典的初始化與啟動加載的主要流程,需要的朋友可以參考下

MySQL 8.0數(shù)據(jù)字典簡介

數(shù)據(jù)字典(Data Dictionary, DD)用來存儲數(shù)據(jù)庫內(nèi)部對象的信息,這些信息也被稱為元數(shù)據(jù)(Metadata),包括schema名稱、表結(jié)構(gòu)、存儲過程的定義等。

圖1 MySQL 8.0之前的數(shù)據(jù)字典

圖片來源:MySQL 8.0 Data Dictionary: Background and Motivation

如圖1所示,MySQL 8.0之前的元數(shù)據(jù),分散存儲在許多不同的位置,包括各種元數(shù)據(jù)文件,不支持事務(wù)的表和存儲引擎特有的數(shù)據(jù)字典等;Server層和存儲引擎層有各自的數(shù)據(jù)字典,其中一部分是重復(fù)的。

以上的設(shè)計導(dǎo)致支持原子的DDL變得很困難,因此MySQL 8.0之前,如果DDL過程中發(fā)生crash,后期的恢復(fù)很容易出現(xiàn)各種問題,導(dǎo)致表無法訪問、復(fù)制異常等。

如圖2所示,MySQL 8.0使用支持事務(wù)的InnoDB存儲引擎作來存儲元數(shù)據(jù),實現(xiàn)數(shù)據(jù)字典的統(tǒng)一管理。這個改進消除了元數(shù)據(jù)存儲的冗余,通過支持原子DDL,實現(xiàn)了DDL的crash safe。

圖2 MySQL 8.0數(shù)據(jù)字典

圖片來源:MySQL 8.0: Data Dictionary Architecture and Design

數(shù)據(jù)字典表都是隱藏的,只有在debug編譯模式下,可以通過設(shè)置開關(guān)set debug='+d,skip_dd_table_access_check'來直接查看數(shù)據(jù)字典表。

mysql> set debug='+d,skip_dd_table_access_check';
Query OK, 0 rows affected (0.01 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 |
| column_statistics            |         1 | System | BASE TABLE |
| column_type_elements         |         1 | System | BASE TABLE |
| columns                      |         1 | System | BASE TABLE |
| dd_properties                |         1 | System | BASE TABLE |
| events                       |         1 | System | BASE TABLE |
| foreign_key_column_usage     |         1 | System | BASE TABLE |
| foreign_keys                 |         1 | System | BASE TABLE |
| index_column_usage           |         1 | System | BASE TABLE |
| index_partitions             |         1 | System | BASE TABLE |
| index_stats                  |         1 | System | BASE TABLE |
| indexes                      |         1 | System | BASE TABLE |
| innodb_ddl_log               |         1 | System | BASE TABLE |
| innodb_dynamic_metadata      |         1 | System | BASE TABLE |
| parameter_type_elements      |         1 | System | BASE TABLE |
| parameters                   |         1 | System | BASE TABLE |
| resource_groups              |         1 | System | BASE TABLE |
| routines                     |         1 | System | BASE TABLE |
| schemata                     |         1 | System | BASE TABLE |
| st_spatial_reference_systems |         1 | System | BASE TABLE |
| table_partition_values       |         1 | System | BASE TABLE |
| table_partitions             |         1 | System | BASE TABLE |
| table_stats                  |         1 | System | BASE TABLE |
| tables                       |         1 | System | BASE TABLE |
| tablespace_files             |         1 | System | BASE TABLE |
| tablespaces                  |         1 | System | BASE TABLE |
| triggers                     |         1 | System | BASE TABLE |
| view_routine_usage           |         1 | System | BASE TABLE |
| view_table_usage             |         1 | System | BASE TABLE |
+------------------------------+-----------+--------+------------+
32 rows in set (0.01 sec)

上面查詢得到的表就是隱藏的數(shù)據(jù)字典表,MySQL的元數(shù)據(jù)存儲在這些表中。

在release編譯模式下,如果要查看數(shù)據(jù)字典信息,只能通過INFORMATION_SCHEMA中的視圖來查詢。例如,可以通過視圖information_schema.tables查詢數(shù)據(jù)字典表mysql.tables。

mysql> select TABLE_SCHEMA,TABLE_NAME,TABLE_TYPE,ENGINE
    -> from information_schema.tables
    -> where TABLE_SCHEMA = 'sbtest' limit 1;
+--------------+------------+------------+--------+
| TABLE_SCHEMA | TABLE_NAME | TABLE_TYPE | ENGINE |
+--------------+------------+------------+--------+
| sbtest       | sbtest1    | BASE TABLE | InnoDB |
+--------------+------------+------------+--------+
1 row in set (0.00 sec)

數(shù)據(jù)字典表的相關(guān)代碼

數(shù)據(jù)字典的代碼位于sql/dd目錄,所有數(shù)據(jù)字典相關(guān)的信息都在dd這個命名空間中,各數(shù)據(jù)字典表本身的定義位于sql/dd/impl/tables目錄的代碼中,可以理解為數(shù)據(jù)字典表的元數(shù)據(jù)在代碼中已經(jīng)定義好了。

以存儲schema信息的schemata表為例,其類的聲明如下:

class Schemata : public Entity_object_table_impl {
public:
  // ...  
 // 所包含的字段  enum enum_fields {
    FIELD_ID,
    FIELD_CATALOG_ID,
    FIELD_NAME,
    FIELD_DEFAULT_COLLATION_ID,
    FIELD_CREATED,
    FIELD_LAST_ALTERED,
    FIELD_OPTIONS,
    FIELD_DEFAULT_ENCRYPTION,
    FIELD_SE_PRIVATE_DATA,
    NUMBER_OF_FIELDS  // Always keep this entry at the end of the enum  };
  // 所包含的索引
  enum enum_indexes {
    INDEX_PK_ID = static_cast<uint>(Common_index::PK_ID),
    INDEX_UK_CATALOG_ID_NAME = static_cast<uint>(Common_index::UK_NAME),
    INDEX_K_DEFAULT_COLLATION_ID
  };
  // 所包含的外鍵
  enum enum_foreign_keys { FK_CATALOG_ID, FK_DEFAULT_COLLATION_ID };
  // ...
};

其構(gòu)造函數(shù)定義了該表的名稱、各字段、索引和外鍵等信息,以及該表默認存儲的數(shù)據(jù)信息,如下所示:

Schemata::Schemata() {
  // 表名  m_target_def.set_table_name("schemata");
  // 字段定義
  m_target_def.add_field(FIELD_ID, "FIELD_ID",
                         "id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT");
  // ...
  // 索引定義
  m_target_def.add_index(INDEX_PK_ID, "INDEX_PK_ID", "PRIMARY KEY (id)");
  // ...
  // 外鍵定義
  m_target_def.add_foreign_key(FK_CATALOG_ID, "FK_CATALOG_ID",
                               "FOREIGN KEY (catalog_id) REFERENCES \ 
                               catalogs(id)");
  // ...
  // 初始化時額外需要執(zhí)行的DML語句
  m_target_def.add_populate_statement(
      "INSERT INTO schemata (catalog_id, name, default_collation_id, created, "
      "last_altered, options, default_encryption, se_private_data) VALUES "
      "(1,'information_schema',33, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, "
      "NULL, 'NO', NULL)");
}

在初始化和啟動時,會使用Object_table_definition_impl::get_ddl()函數(shù)來獲取m_target_def中信息所生成的DDL語句,創(chuàng)建出schemata表;使用Object_table_definition_impl::get_dml()獲取DML語句,用于初始化表中的數(shù)據(jù)。

dd::tables::Schemata類的繼承關(guān)系,如圖3。所有的數(shù)據(jù)字典表對應(yīng)的類,最終都是派生自dd::Object_table,便于統(tǒng)一處理。

圖3 dd::tables::Schemata類

對于這些表中存儲的元數(shù)據(jù)所對應(yīng)的對象,或者說這些表中的每一行數(shù)據(jù)所對應(yīng)的一個對象,比如一個schema、table、column等,代碼中也有對應(yīng)的類。

還是以schema為例,它對應(yīng)的類是dd::Schema,實現(xiàn)類是dd::Schema_impl,代表的是schema這種數(shù)據(jù)庫內(nèi)部對象,也是mysql.schemata表中的一行。

所有數(shù)據(jù)字典中所存儲的對象在代碼中的基類都是dd::Weak_object,如圖4:

圖4 dd::Schema_impl類

schema的id和name在dd::Entity_object_impl中,其他字段在實現(xiàn)類dd::Schema_impl中。

實現(xiàn)類dd::Schema_impl主要實現(xiàn)了對于元數(shù)據(jù)對象的各屬性的讀寫訪問,與從數(shù)據(jù)字典中的元數(shù)據(jù)表schemata的行記錄中,存取元數(shù)據(jù)的接口。

主要相關(guān)接口如下:

class Weak_object_impl_ : virtual public Weak_object {
  // ...
 public:
  // 存儲記錄到元數(shù)據(jù)表
  virtual bool store(Open_dictionary_tables_ctx *otx); 
 // 刪除元數(shù)據(jù)表中的記錄  bool drop(Open_dictionary_tables_ctx *otx) const;
 public:
  // 從元數(shù)據(jù)表的記錄中提取各屬性字段
  virtual bool restore_attributes(const Raw_record &r) = 0;
  // 保存各屬性到元數(shù)據(jù)表的記錄
  virtual bool store_attributes(Raw_record *r) = 0;
  // 讀取相關(guān)對象的信息,如表上的索引等
  virtual bool restore_children(Open_dictionary_tables_ctx *) { return false; }
  // 存儲相關(guān)對象的信息
  virtual bool store_children(Open_dictionary_tables_ctx *) { return false; }
  // 刪除相關(guān)對象的信息
  virtual bool drop_children(Open_dictionary_tables_ctx *) const {
    return false;
  }
};

dd::Schema_impl主要實現(xiàn)了store_attributes和restore_attributes接口,依據(jù)dd::tables::Schemata中的表定義信息,讀取或存儲schema的各個屬性信息。

依據(jù)以上介紹的,數(shù)據(jù)字典表的類與數(shù)據(jù)庫內(nèi)部對象的類,結(jié)合InnoDB存儲引擎的接口,實現(xiàn)了對于存儲于數(shù)據(jù)字典各個表中的元數(shù)據(jù)的讀寫訪問。

例如,存儲新建的database的元數(shù)據(jù)到schema內(nèi)存對象中:

#0  dd::Schema_impl::store_attributes
#1  in dd::Weak_object_impl::store
#2  in dd::cache::Storage_adapter::store<dd::Schema>
#3  in dd::cache::Dictionary_client::store<dd::Schema>
#4  in dd::create_schema
#5  in mysql_create_db
#6  in mysql_execute_command...

持久化到對應(yīng)的InnoDB表mysql.schemata中:

#0  ha_innobase::write_row
#1  in handler::ha_write_row
#2  in dd::Raw_new_record::insert
#3  in dd::Weak_object_impl::store
#4  in dd::cache::Storage_adapter::store<dd::Schema>
#5  in dd::cache::Dictionary_client::store<dd::Schema>
#6  in dd::create_schema
#7  in mysql_create_db
#8  in mysql_execute_command
...

數(shù)據(jù)字典的初始化

初始化MySQL數(shù)據(jù)庫實例時,即執(zhí)行mysqld -initialize時,main函數(shù)會啟動一個bootstrap線程來進行數(shù)據(jù)字典的初始化,并等待其完成。

數(shù)據(jù)字典的初始化函數(shù)入口是dd::bootstrap::initialize,主要流程如下:

圖5 數(shù)據(jù)字典初始化流程

其中,DDSE指的是Data Dictionary Storage Engine,數(shù)據(jù)字典的存儲引擎,即InnoDB。DDSE初始化過程主要是對InnoDB進行必要的初始化,并獲取DDSE代碼中預(yù)先定義好的表的定義與表空間的定義。

InnoDB預(yù)定義的數(shù)據(jù)字典表:

  • innodb_dynamic_metadata

InnoDB的動態(tài)元數(shù)據(jù),包括表的自增列值等。

  • innodb_table_stats

InnoDB表的統(tǒng)計信息。

  • innodb_index_stats

InnoDB索引的統(tǒng)計信息。

  • innodb_ddl_log

存儲InnoDB的DDL日志,用于原子DDL的實現(xiàn)。

InnoDB預(yù)定義的系統(tǒng)表空間:

  • mysql

數(shù)據(jù)字典的表空間,數(shù)據(jù)字典表都在這個表空間中。

  • innodb_system

InnoDB的系統(tǒng)表空間,主要包含InnoDB的Change Buffer;如果不使用file-per-table或指定其他表空間,用戶表也會創(chuàng)建在這個表空間中。

InnoDB的ddse_dict_init接口的實現(xiàn)為innobase_ddse_dict_init,會先調(diào)用innobase_init_files初始化所需文件并啟動InnoDB。

主要代碼流程如下:

static bool innobase_ddse_dict_init(
    dict_init_mode_t dict_init_mode, uint,
 List<const dd::Object_table> *tables,List<const Plugin_tablespace> *tablespaces) {
// ...
// 初始化文件并啟動InnoDB
if (innobase_init_files(dict_init_mode, tablespaces)) {
return true;
  }
// innodb_dynamic_metadata表的定義
  dd::Object_table *innodb_dynamic_metadata =
      dd::Object_table::create_object_table();
  innodb_dynamic_metadata->set_hidden(true);
  dd::Object_table_definition *def =
      innodb_dynamic_metadata->target_table_definition();
  def->set_table_name("innodb_dynamic_metadata");
  def->add_field(0, "table_id", "table_id BIGINT UNSIGNED NOT NULL");
  def->add_field(1, "version", "version BIGINT UNSIGNED NOT NULL");
  def->add_field(2, "metadata", "metadata BLOB NOT NULL");
  def->add_index(0, "index_pk", "PRIMARY KEY (table_id)");
// ...
/* innodb_table_stats、innodb_index_stats、innodb_ddl_log表的定義 */
// ...
}

在DDSE初始化并啟動的基礎(chǔ)上,就可以進行剩下的數(shù)據(jù)字典初始化過程,主要就是創(chuàng)建數(shù)據(jù)字典的schema和表。這些表的元數(shù)據(jù)在執(zhí)行flush_meta_data時進行持久化。

值得注意的是表mysql.dd_properties,它會存儲版本信息等數(shù)據(jù)字典的屬性,還會存儲其他數(shù)據(jù)字典表的定義、id、se_private_data等信息,在數(shù)據(jù)庫啟動時使用。

數(shù)據(jù)字典初始化整體執(zhí)行的函數(shù)調(diào)用總結(jié),如圖6:

圖6 數(shù)據(jù)字典初始化的函數(shù)調(diào)用

數(shù)據(jù)字典的啟動

數(shù)據(jù)字典的啟動過程所執(zhí)行的函數(shù)與初始化時十分相似,大部分在函數(shù)內(nèi)部通過opt_initialize全局變量來區(qū)分初始化和啟動,執(zhí)行不同的代碼邏輯。

與初始化的主要區(qū)別是元數(shù)據(jù)不再需要生成并持久化到存儲,而是從存儲讀取已有的元數(shù)據(jù)。InnoDB文件是打開已有的,而不是新建。

數(shù)據(jù)字典啟動的入口是dd::upgrade_57::do_pre_checks_and_initialize_dd。這里雖然有'upgrade_57'這種名稱的namespace,但是正常的啟動也是從這里開始。

與初始化相同,數(shù)據(jù)字典的啟動也是先準備好DDSE,即啟動InnoDB,然后再進行后面啟動數(shù)據(jù)字典的步驟。打開數(shù)據(jù)字典之前,InnoDB會進行數(shù)據(jù)字典的恢復(fù),確保重啟前的DDL都正常的提交或回滾,數(shù)據(jù)字典元數(shù)據(jù)和數(shù)據(jù)是處于一致的狀態(tài)。

dd::upgrade_57::restart_dictionary調(diào)用dd::bootstrap::restart,后面的啟動步驟由它來實現(xiàn),主要過程如下。

注意這里的創(chuàng)建表,是創(chuàng)建內(nèi)存中的對象,不是物理上新創(chuàng)建一個表。這些表的元數(shù)據(jù)都已經(jīng)在初始化時持久化了。

bool restart(THD *thd) {
  bootstrap::DD_bootstrap_ctx::instance().set_stage(bootstrap::Stage::STARTED);
// 獲取預(yù)定義的系統(tǒng)tablespace的元數(shù)據(jù)(mysql和innodb_system)
  store_predefined_tablespace_metadata(thd);
if (create_dd_schema(thd) ||  // 創(chuàng)建schema:'mysql'
      initialize_dd_properties(thd) ||  // 創(chuàng)建mysql.dd_properties表并從中獲取版本號等信息 
     create_tables(thd, nullptr) ||  // 創(chuàng)建數(shù)據(jù)字典中其他的表
      sync_meta_data(thd) ||  // 從存儲讀取數(shù)據(jù)字典相關(guān)的schema、tablespace和表的元數(shù)據(jù),進行同步
/* 打開InnoDB的數(shù)據(jù)字典表(innodb_dynamic_metadata, innodb_table_stats, innodb_index_stats,
      innodb_ddl_log),加載所有InnoDB的表空間 */
      DDSE_dict_recover(thd, DICT_RECOVERY_RESTART_SERVER, 
                       d->get_actual_dd_version(thd)) ||      
      upgrade::do_server_upgrade_checks(thd) ||  // 檢查是否能夠升級(如果需要的話,正常啟動不涉及)
      upgrade::upgrade_tables(thd) ||  // 升級數(shù)據(jù)字典表的定義及其中的元數(shù)據(jù)(如果需要的話,正常啟動不涉及)
      repopulate_charsets_and_collations(thd) ||  // 更新charset和collation信息
      verify_contents(thd) ||  // 驗證數(shù)據(jù)字典內(nèi)容
      update_versions(thd, false)) {  // 更新版本信息到dd_properties表
return true;
  }
// ...
  bootstrap::DD_bootstrap_ctx::instance().set_stage(bootstrap::Stage::FINISHED);
  LogErr(INFORMATION_LEVEL, ER_DD_VERSION_FOUND, d->get_actual_dd_version(thd));
return false;
}

啟動時各個數(shù)據(jù)字典表的根頁面信息是從 mysql.dd_properties表中獲取的,通過該頁面可以訪問對應(yīng)表的所有數(shù)據(jù)。

mysql.dd_properties表的根頁面是固定的,并且它里面保存了數(shù)組字典表本身的元數(shù)據(jù)。相關(guān)函數(shù):dd::get_se_private_data()。

小結(jié)

MySQL 8.0新設(shè)計實現(xiàn)的數(shù)據(jù)字典,解決了之前版本的數(shù)據(jù)字典冗余,DDL原子性、crash safe等問題。通過對數(shù)據(jù)字典的初始化流程,以及數(shù)據(jù)字典正常重啟時加載流程的梳理,希望讀者對新數(shù)據(jù)字典的實現(xiàn)和運行有一個更深入的了解。

以上就是MySQL 8.0數(shù)據(jù)字典的初始化與啟動流程的詳細內(nèi)容,更多關(guān)于MySQL 8.0數(shù)據(jù)字典的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • MySQL切分函數(shù)substring()的具體使用

    MySQL切分函數(shù)substring()的具體使用

    這篇文章主要介紹了MySQL切分函數(shù)substring()的具體使用,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • Mysql查看死鎖與解除死鎖的深入講解

    Mysql查看死鎖與解除死鎖的深入講解

    這篇文章主要給大家介紹了關(guān)于Mysql查看死鎖與解除死鎖的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • MySQL三種打開方式詳細圖文教程

    MySQL三種打開方式詳細圖文教程

    MySQL有多種打開方式,具體取決于你的操作系統(tǒng)和安裝方式,下面這篇文章主要給大家介紹了關(guān)于MySQL三種打開方式的相關(guān)資料,文中通過圖文介紹的非常詳細,需要的朋友可以參考下
    2024-07-07
  • MySQL之鎖類型解讀

    MySQL之鎖類型解讀

    MySQL鎖類型包括讀鎖(共享鎖)和寫鎖(排他鎖),并介紹了意向鎖、自增鎖、元數(shù)據(jù)鎖、行級鎖和間隙鎖等概念,悲觀鎖和樂觀鎖是兩種不同的鎖設(shè)計思想,悲觀鎖在每次操作前加鎖,適用于并發(fā)沖突多的場景;樂觀鎖在更新時判斷數(shù)據(jù)是否被修改
    2025-02-02
  • MySQL中SQL Mode的查看與設(shè)置詳解

    MySQL中SQL Mode的查看與設(shè)置詳解

    在本篇文章里小編給各位分享的是關(guān)于MySQL中SQL Mode的查看與設(shè)置詳解內(nèi)容,需要的朋友們可以參考下。
    2020-03-03
  • mysql實現(xiàn)將data文件直接導(dǎo)入數(shù)據(jù)庫文件

    mysql實現(xiàn)將data文件直接導(dǎo)入數(shù)據(jù)庫文件

    這篇文章主要介紹了mysql實現(xiàn)將data文件直接導(dǎo)入數(shù)據(jù)庫文件問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • MySql狀態(tài)查看方法 MySql如何查看連接數(shù)和狀態(tài)?

    MySql狀態(tài)查看方法 MySql如何查看連接數(shù)和狀態(tài)?

    如果是root帳號,你能看到所有用戶的當(dāng)前連接。如果是其它普通帳號,只能看到自己占用的連接
    2012-11-11
  • MySQL8.0.21.0社區(qū)版安裝教程(圖文詳解)

    MySQL8.0.21.0社區(qū)版安裝教程(圖文詳解)

    這篇文章主要介紹了MySQL8.0.21.0社區(qū)版安裝教程,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08
  • MySQL中使用自定義變量 編寫偷懶的UNION示例

    MySQL中使用自定義變量 編寫偷懶的UNION示例

    以下是對MySQL中使用自定義變量,編寫一個UNION的示例進行了詳細的介紹,需要的朋友可以過來參考下
    2013-07-07
  • MySQL數(shù)據(jù)庫中把int轉(zhuǎn)化varchar引發(fā)的慢查詢

    MySQL數(shù)據(jù)庫中把int轉(zhuǎn)化varchar引發(fā)的慢查詢

    這篇文章主要介紹了MySQL數(shù)據(jù)庫中把int轉(zhuǎn)化varchar引發(fā)的慢查詢 的相關(guān)資料,非常不錯具有參考借鑒價值,需要的朋友可以參考下
    2016-07-07

最新評論