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


https://github.com/stoneatom/stonedb
設(shè)計:小艾
審核:丁奇、李浩
編輯:宇亭
作者:王若添
中國科學(xué)技術(shù)大學(xué)-軟件工程-在讀碩士、StoneDB 內(nèi)核研發(fā)實習生
performance_schema 簡介
MySQL 啟動后會自動創(chuàng)建四個 database
其中的 performance schema 用于監(jiān)控 MySQL server 在一個較低級別的運行過程中的資源消耗、資源等待等情況。它提供了一種在數(shù)據(jù)庫運行時實時檢查 server 的內(nèi)部執(zhí)行情況的方法,該數(shù)據(jù)庫主要關(guān)注數(shù)據(jù)庫運行過程中的性能相關(guān)的數(shù)據(jù),與更為常見的 information_schema 不同,information_schema 主要關(guān)注 server 運行過程中的元數(shù)據(jù)信息。
performance_schema 中的事件只記錄在本地 server 的 performance_schema 中,其表中數(shù)據(jù)發(fā)生變化時不會被寫入 binlog 中,也不會通過復(fù)制機制被復(fù)制到其他 server 中。
表的分類
可以將 performance_schema 庫下的表按照監(jiān)視不同的緯度就行分組。
語句事件記錄表,這些表記錄了語句事件信息
等待事件記錄表,與語句事件類型的相關(guān)記錄表類似
事務(wù)事件記錄表,記錄事務(wù)相關(guān)的事件的表
使用場景
對于語句事件記錄表中的 events_statements_summary_by_digest 表舉例,這個表記錄了基于 SQL 語句摘要的統(tǒng)計信息。如果我們想要了解該 stonedb 進程上執(zhí)行過的所有類型 SQL 的頻次,我們可以使用 SELECT DIGEST_TEXT,COUNT_STAR FROM events_statements_summary_by_digest 查詢該表,其中
DIGEST_TEXT: 這個列是 SQL 語句的標準化版本,即刪除了 SQL 語句中的特定數(shù)據(jù)(例如,具體的值、表名、列名等)后的 SQL 語句。所有邏輯上相同的 SQL 語句(即使具體的值不同)都會有相同的 DIGEST_TEXT。這使得我們可以統(tǒng)計和分析相同邏輯 SQL 語句的執(zhí)行情況。
COUNT_STAR: 這個列是每個 SQL 語句摘要的執(zhí)行次數(shù)。這可以幫助我們識別哪些 SQL 語句被執(zhí)行的次數(shù)最多,可能對系統(tǒng)的性能影響最大。
這個查詢返回的結(jié)果就是每種 SQL 語句的標準化版本及其執(zhí)行次數(shù)。這可以幫助我們理解哪些類型的 SQL 語句最常被執(zhí)行,進而可以對這些 SQL 語句進行優(yōu)化以提高系統(tǒng)的性能。
創(chuàng)建新的元數(shù)據(jù)表
如果我們希望在 performance_schema 庫中新增加一個描述列式二級引擎列相關(guān)信息的元數(shù)據(jù)表 mock_columns,用來描述加載到 mock_columns 的列式數(shù)據(jù)情況,比如被加載到了 mock 引擎中的列名列號,所屬表名,ndv(number of disctinct value)等信息。
以 t1 表為例
執(zhí)行下面的 sql 可以將 innodb 中數(shù)據(jù) load 到二級引擎 mock 中
在代碼層面,我們需要在加載 innodb 表到 mock 引擎(sql_table.cc 中的 secondary_engine_load_table 函數(shù))的同時將各列的元數(shù)據(jù)信息存起來,比如可以存在一個全局的 meta_column_columns 映射表中,以便之后執(zhí)行器在查詢中可以讀到這些列信息。
函數(shù)調(diào)用棧如下圖:

查詢元數(shù)據(jù)表
將 t1 表加載到 mock 引擎中后,我們就可以執(zhí)行 SELECT * FROM mock_columns 進行查詢。
代碼實現(xiàn)上簡單來說我們需要新建一個類 table_mock_columns 實現(xiàn) PFS_engine_table 這個抽象類,在深入細節(jié)之前,先了解下 MySQL 中存儲引擎 handler 接口的基本概念:
MySQL 架構(gòu)可分為 SQL 層和存儲引擎層,而且支持插件式存儲引擎,不同的存儲引擎只需實現(xiàn) handler 這個抽象類包含的方法即可作為 MySQL 的引擎進行數(shù)據(jù)存取,常見的存儲引擎有 innodb、myisam 等(上文提到的 mock 引擎也是一種存儲引擎)。而負責 MySQL 元數(shù)據(jù)信息的引擎是 perfschema 引擎。顯然 ha_perfschema 需要繼承 handler 抽象類,ha_perfschema 類主要的成員變量 PFS_engine_table *m_table,performance_schema 中所有的 table 類都需要繼承該抽象類(也可以理解該類的一個主要作用是充當讀取記錄的游標,詳細信息見后文)。
PFS_engine_table 的初始化
PFS_engine_table 中的存在一個類型為 PFS_engine_table_share *的成員變量 m_table_share,
其數(shù)據(jù)被所有打開該表的句柄共享的。其中包含一些回調(diào)函數(shù),如打開表 m_open_table,寫操作 m_write_row 和刪除所有行 m_delete_all_rows 等。
還包含一個 Plugin_table 類型的代表表定義的變量 m_table_def(類似于 CREATE TABLE 類型 SQL 的形式,包括表名,列名及列類型等信息)。我們需要做的就是在創(chuàng)建 PFS_engine_table 類型的 column 表時填充這些變量和函數(shù)。如定義表 mock_columns 的表結(jié)構(gòu):
實現(xiàn)相關(guān)虛函數(shù)
PFS_engine_table 中主要的虛函數(shù)有以下三個(暫時不關(guān)注索引相關(guān)的讀取函數(shù)):
如果我們希望在 performance_schema 庫下新增一張元數(shù)據(jù)表,需要重載以上三個方法,rnd_init 函數(shù)做一些初始化工作,rnd_next 函數(shù)從全局映射表 meta_column_columns 中將下一條記錄取到 m_table 游標中,read_row_values 函數(shù)負責將 m_table 游標中存儲的數(shù)據(jù)讀出并返回。
查詢該表時候,MySQL 執(zhí)行器中的函數(shù)調(diào)用鏈如下 (參數(shù)已省略):TableScanIterator::Read()→handler::ha_rnd_next()→ha_perfschema::rnd_next()→table_mock_columns::rnd_next(), 執(zhí)行后會將下一條記錄取出到 m_table 游標中暫存,然后 ha_perfschema::rnd_next()會調(diào)用 read_row_values()函數(shù), 將 m_table 中的一行數(shù)據(jù)讀出填充到 Field 列表字段查詢結(jié)束。
最后的查詢結(jié)果如下:
刪除元數(shù)據(jù)表
performance_schema 中的表是不進行持久化的,這些表主要用來收集和存儲 MySQL 服務(wù)器的實時性能數(shù)據(jù),以便于用戶進行性能分析和問題診斷。這些數(shù)據(jù)存儲在內(nèi)存中,并且在 MySQL 服務(wù)器重啟后會被清空。這種設(shè)計是有意為之的,因為 performance_schema 中的數(shù)據(jù)主要用于實時性能分析,而不是長期存儲。如果需要長期保留這些數(shù)據(jù),我們需要自己定期收集并存儲這些數(shù)據(jù)。
用戶也可以執(zhí)行如下 SQL 將從 innodb 主引擎中加載到二級引擎 mock 的表卸手動載掉:
執(zhí)行表卸載的時候需要自動把加載到二級引擎 mock 上的表中對應(yīng)的列信息刪除掉,對應(yīng)到源碼層面就是當用戶執(zhí)行該 SQL 時,mock 引擎將之前加載到 meta_mock_columns 映射表中需要被卸載表的數(shù)據(jù)清除掉。
結(jié)束語
經(jīng)過對 performance_schema 相關(guān)表的介紹和源碼探索,我們已對如何在 performance_schema 庫中創(chuàng)建一張我們需要的元數(shù)據(jù)表有了較為詳細的理解。希望這篇分析能為您在深入研究或進行二次開發(fā)時提供有益的參考。
本文基于 MySQL 8.0.33 源碼進行分析
StoneDB 介紹
StoneDB 是石原子科技自主設(shè)計研發(fā)的國內(nèi)首款完全兼容于 MySQL 生態(tài)的開源 一體化實時 HTAP 數(shù)據(jù)庫產(chǎn)品,具備行列混存、智能索引等核心特性,為 MySQL 數(shù)據(jù)庫提供在線數(shù)據(jù)實時就近分析服務(wù),能夠高效解決 MySQL 數(shù)據(jù)庫在分析型應(yīng)用場景中面臨的能力問題。同時,StoneDB 使用多存儲引擎架構(gòu)的設(shè)計,事務(wù)引擎具有數(shù)據(jù)強一致特性,具備完整的事務(wù)并發(fā)處理能力,使得 StoneDB 可以替代 MySQL 數(shù)據(jù)庫滿足在線事務(wù)處理場景的需求,使用 MySQL 的用戶,通過 StoneDB 可以實現(xiàn) TP+AP 混合負載,分析性能提升 10?倍以上顯著提升,不需要進行數(shù)據(jù)遷移,也無需與其他 AP 集成,彌補 MySQL 分析領(lǐng)域的空白。
開源倉庫https://github.com/stoneatom/stonedb
加入StoneDB社區(qū)
Github:https://github.com/stoneatom/stonedb
Gitee:https://gitee.com/StoneDB/stonedb
社區(qū)官網(wǎng):https://stonedb.io/
嗶哩嗶哩:https://space.bilibili.com/1154290084
Twitter:https://twitter.com/StoneDataBase
Linkedin:https://www.linkedin.com/in/stonedb/