為MySQL新增一張performance_schema表 | StoneDB 技術(shù)分享會(huì) #4

image.png

設(shè)計(jì):小艾
審核:丁奇、李浩
編輯:宇亭

作者:王若添
中國科學(xué)技術(shù)大學(xué)-軟件工程-在讀碩士、StoneDB 內(nèi)核研發(fā)實(shí)習(xí)生

performance_schema 簡介

MySQL 啟動(dòng)后會(huì)自動(dòng)創(chuàng)建四個(gè) database

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+

其中的 performance schema 用于監(jiān)控 MySQL server 在一個(gè)較低級別的運(yùn)行過程中的資源消耗、資源等待等情況。它提供了一種在數(shù)據(jù)庫運(yùn)行時(shí)實(shí)時(shí)檢查 server 的內(nèi)部執(zhí)行情況的方法,該數(shù)據(jù)庫主要關(guān)注數(shù)據(jù)庫運(yùn)行過程中的性能相關(guān)的數(shù)據(jù),與更為常見的 information_schema 不同,information_schema 主要關(guān)注 server 運(yùn)行過程中的元數(shù)據(jù)信息。

performance_schema 中的事件只記錄在本地 server 的 performance_schema 中,其表中數(shù)據(jù)發(fā)生變化時(shí)不會(huì)被寫入 binlog 中,也不會(huì)通過復(fù)制機(jī)制被復(fù)制到其他 server 中。

表的分類

可以將 performance_schema 庫下的表按照監(jiān)視不同的緯度就行分組。

  • 語句事件記錄表,這些表記錄了語句事件信息
mysql> show tables like '%statement%';
+----------------------------------------------------+
| Tables_in_performance_schema (%statement%)         |
+----------------------------------------------------+
| events_statements_current                          |
| events_statements_histogram_by_digest              |
| events_statements_history                          |
| events_statements_summary_by_digest                |
| events_statements_summary_by_host_by_event_name    |
| ...                                                |
  • 等待事件記錄表,與語句事件類型的相關(guān)記錄表類似
mysql> show tables like '%wait%';
+-----------------------------------------------+
| Tables_in_performance_schema (%wait%)         |
+-----------------------------------------------+
| data_lock_waits                               |
| events_waits_current                          |
| events_waits_history                          |
| events_waits_history_long                     |
| ...                                           |
  • 事務(wù)事件記錄表,記錄事務(wù)相關(guān)的事件的表
mysql> show tables like '%transaction%';
+------------------------------------------------------+
| Tables_in_performance_schema (%transaction%)         |
+------------------------------------------------------+
| binary_log_transaction_compression_stats             |
| events_transactions_current                          |
| events_transactions_history                          |
| ...                                                  |

使用場景

對于語句事件記錄表中的 events_statements_summary_by_digest 表舉例,這個(gè)表記錄了基于 SQL 語句摘要的統(tǒng)計(jì)信息。如果我們想要了解該 stonedb 進(jìn)程上執(zhí)行過的所有類型 SQL 的頻次,我們可以使用 SELECT DIGEST_TEXT,COUNT_STAR FROM events_statements_summary_by_digest 查詢該表,其中

  • DIGEST_TEXT: 這個(gè)列是 SQL 語句的標(biāo)準(zhǔn)化版本,即刪除了 SQL 語句中的特定數(shù)據(jù)(例如,具體的值、表名、列名等)后的 SQL 語句。所有邏輯上相同的 SQL 語句(即使具體的值不同)都會(huì)有相同的 DIGEST_TEXT。這使得我們可以統(tǒng)計(jì)和分析相同邏輯 SQL 語句的執(zhí)行情況。
  • COUNT_STAR: 這個(gè)列是每個(gè) SQL 語句摘要的執(zhí)行次數(shù)。這可以幫助我們識別哪些 SQL 語句被執(zhí)行的次數(shù)最多,可能對系統(tǒng)的性能影響最大。

這個(gè)查詢返回的結(jié)果就是每種 SQL 語句的標(biāo)準(zhǔn)化版本及其執(zhí)行次數(shù)。這可以幫助我們理解哪些類型的 SQL 語句最常被執(zhí)行,進(jìn)而可以對這些 SQL 語句進(jìn)行優(yōu)化以提高系統(tǒng)的性能。

創(chuàng)建新的元數(shù)據(jù)表

如果我們希望在 performance_schema 庫中新增加一個(gè)描述列式二級引擎列相關(guān)信息的元數(shù)據(jù)表 mock_columns,用來描述加載到 mock_columns 的列式數(shù)據(jù)情況,比如被加載到了 mock 引擎中的列名列號,所屬表名,ndv(number of disctinct value)等信息。

以 t1 表為例

create table t1 (c1 int PRIMAEY_KEY);
// 安裝二級引擎mock的動(dòng)態(tài)鏈接庫
INSTALL PLUGIN mock SONAME "ha_mock.so";
// 指定t1的二級引擎為mock
ALTER TABLE t1 SECONDARY_ENGINE=ha_mock;

執(zhí)行下面的 sql 可以將 innodb 中數(shù)據(jù) load 到二級引擎 mock 中

ALTER TABLE t1 SECONDARY_LOAD;

在代碼層面,我們需要在加載 innodb 表到 mock 引擎(sql_table.cc 中的 secondary_engine_load_table 函數(shù))的同時(shí)將各列的元數(shù)據(jù)信息存起來,比如可以存在一個(gè)全局的 meta_column_columns 映射表中,以便之后執(zhí)行器在查詢中可以讀到這些列信息。

函數(shù)調(diào)用棧如下圖:

image.png

查詢元數(shù)據(jù)表

將 t1 表加載到 mock 引擎中后,我們就可以執(zhí)行 SELECT * FROM mock_columns 進(jìn)行查詢。

代碼實(shí)現(xiàn)上簡單來說我們需要新建一個(gè)類 table_mock_columns 實(shí)現(xiàn) PFS_engine_table 這個(gè)抽象類,在深入細(xì)節(jié)之前,先了解下 MySQL 中存儲(chǔ)引擎 handler 接口的基本概念:

MySQL 架構(gòu)可分為 SQL 層和存儲(chǔ)引擎層,而且支持插件式存儲(chǔ)引擎,不同的存儲(chǔ)引擎只需實(shí)現(xiàn) handler 這個(gè)抽象類包含的方法即可作為 MySQL 的引擎進(jìn)行數(shù)據(jù)存取,常見的存儲(chǔ)引擎有 innodb、myisam 等(上文提到的 mock 引擎也是一種存儲(chǔ)引擎)。而負(fù)責(zé) MySQL 元數(shù)據(jù)信息的引擎是 perfschema 引擎。顯然 ha_perfschema 需要繼承 handler 抽象類,ha_perfschema 類主要的成員變量 PFS_engine_table *m_table,performance_schema 中所有的 table 類都需要繼承該抽象類(也可以理解該類的一個(gè)主要作用是充當(dāng)讀取記錄的游標(biāo),詳細(xì)信息見后文)。

PFS_engine_table 的初始化

PFS_engine_table 中的存在一個(gè)類型為 PFS_engine_table_share *的成員變量 m_table_share,
其數(shù)據(jù)被所有打開該表的句柄共享的。其中包含一些回調(diào)函數(shù),如打開表 m_open_table,寫操作 m_write_row 和刪除所有行 m_delete_all_rows 等。

還包含一個(gè) Plugin_table 類型的代表表定義的變量 m_table_def(類似于 CREATE TABLE 類型 SQL 的形式,包括表名,列名及列類型等信息)。我們需要做的就是在創(chuàng)建 PFS_engine_table 類型的 column 表時(shí)填充這些變量和函數(shù)。如定義表 mock_columns 的表結(jié)構(gòu):

Plugin_table table_mock_columns::s_table_def(
    /* Schema name */
    "performance_schema",
    /* Name */
    "mock_columns",
    /* Definition */
    "  TABLE_ID int unsigned NOT NULL,\n"
    "  TABLE_NAME VARCHAR(64) NOT NULL,\n"
    "  COLUMN_ID int unsigned NOT NULL,\n"
    "  NDV bigint unsigned NOT NULL,\n"
    "  ENCODING varchar(64) DEFAULT NULL,\n"
    /* Options */
    " ENGINE=PERFORMANCE_SCHEMA CHARACTER SET utf8mb4 COLLATE utf8mb4_bin",
    /* Tablespace */
    nullptr);
)

實(shí)現(xiàn)相關(guān)虛函數(shù)

PFS_engine_table 中主要的虛函數(shù)有以下三個(gè)(暫時(shí)不關(guān)注索引相關(guān)的讀取函數(shù)):

int rnd_init(bool scan)
int rnd_next(void)
int read_row_values(TABLE *table, unsigned char *buf, Field **fields, bool read_all)

如果我們希望在 performance_schema 庫下新增一張?jiān)獢?shù)據(jù)表,需要重載以上三個(gè)方法,rnd_init 函數(shù)做一些初始化工作,rnd_next 函數(shù)從全局映射表 meta_column_columns 中將下一條記錄取到 m_table 游標(biāo)中,read_row_values 函數(shù)負(fù)責(zé)將 m_table 游標(biāo)中存儲(chǔ)的數(shù)據(jù)讀出并返回。

查詢該表時(shí)候,MySQL 執(zhí)行器中的函數(shù)調(diào)用鏈如下 (參數(shù)已省略):TableScanIterator::Read()→handler::ha_rnd_next()→ha_perfschema::rnd_next()→table_mock_columns::rnd_next(), 執(zhí)行后會(huì)將下一條記錄取出到 m_table 游標(biāo)中暫存,然后 ha_perfschema::rnd_next()會(huì)調(diào)用 read_row_values()函數(shù), 將 m_table 中的一行數(shù)據(jù)讀出填充到 Field 列表字段查詢結(jié)束。

最后的查詢結(jié)果如下:

mysql> SELECT * FROM `mock_columns`;
+----------+------------+------------+-----+------------+
| TABLE_ID | TABLE_NAME |  COLUMN_ID | NDV |  ENCODING  |
+----------+------------+------------------+------------+
|       87 |         t1 |          0 |   0 | dictionary |
+----------+------------+------------------+------------+
1 row in set (4.68 sec)

刪除元數(shù)據(jù)表

performance_schema 中的表是不進(jìn)行持久化的,這些表主要用來收集和存儲(chǔ) MySQL 服務(wù)器的實(shí)時(shí)性能數(shù)據(jù),以便于用戶進(jìn)行性能分析和問題診斷。這些數(shù)據(jù)存儲(chǔ)在內(nèi)存中,并且在 MySQL 服務(wù)器重啟后會(huì)被清空。這種設(shè)計(jì)是有意為之的,因?yàn)?performance_schema 中的數(shù)據(jù)主要用于實(shí)時(shí)性能分析,而不是長期存儲(chǔ)。如果需要長期保留這些數(shù)據(jù),我們需要自己定期收集并存儲(chǔ)這些數(shù)據(jù)。

用戶也可以執(zhí)行如下 SQL 將從 innodb 主引擎中加載到二級引擎 mock 的表卸手動(dòng)載掉:

ALTER TABLE t1 SECONDARY_UNLOAD;

執(zhí)行表卸載的時(shí)候需要自動(dòng)把加載到二級引擎 mock 上的表中對應(yīng)的列信息刪除掉,對應(yīng)到源碼層面就是當(dāng)用戶執(zhí)行該 SQL 時(shí),mock 引擎將之前加載到 meta_mock_columns 映射表中需要被卸載表的數(shù)據(jù)清除掉。

結(jié)束語

經(jīng)過對 performance_schema 相關(guān)表的介紹和源碼探索,我們已對如何在 performance_schema 庫中創(chuàng)建一張我們需要的元數(shù)據(jù)表有了較為詳細(xì)的理解。希望這篇分析能為您在深入研究或進(jìn)行二次開發(fā)時(shí)提供有益的參考。

?

本文基于 MySQL 8.0.33 源碼進(jìn)行分析

?

StoneDB 介紹

StoneDB 是石原子科技自主設(shè)計(jì)研發(fā)的國內(nèi)首款完全兼容于 MySQL 生態(tài)的開源 一體化實(shí)時(shí) HTAP 數(shù)據(jù)庫產(chǎn)品,具備行列混存、智能索引等核心特性,為 MySQL 數(shù)據(jù)庫提供在線數(shù)據(jù)實(shí)時(shí)就近分析服務(wù),能夠高效解決 MySQL 數(shù)據(jù)庫在分析型應(yīng)用場景中面臨的能力問題。同時(shí),StoneDB 使用多存儲(chǔ)引擎架構(gòu)的設(shè)計(jì),事務(wù)引擎具有數(shù)據(jù)強(qiáng)一致特性,具備完整的事務(wù)并發(fā)處理能力,使得 StoneDB 可以替代 MySQL 數(shù)據(jù)庫滿足在線事務(wù)處理場景的需求,使用 MySQL 的用戶,通過 StoneDB 可以實(shí)現(xiàn) TP+AP 混合負(fù)載,分析性能提升 10 倍以上顯著提升,不需要進(jìn)行數(shù)據(jù)遷移,也無需與其他 AP 集成,彌補(bǔ) MySQL 分析領(lǐng)域的空白。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容