溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

怎么解析與優(yōu)化MySQL 8.0 PFS histogram

發(fā)布時間:2021-10-28 09:26:23 來源:億速云 閱讀:140 作者:iii 欄目:MySQL數(shù)據(jù)庫

這篇文章主要介紹“怎么解析與優(yōu)化MySQL 8.0 PFS histogram”,在日常操作中,相信很多人在怎么解析與優(yōu)化MySQL 8.0 PFS histogram問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”怎么解析與優(yōu)化MySQL 8.0 PFS histogram”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

PartⅠ 引言

線上數(shù)據(jù)庫的運維,往往避不開對語句執(zhí)行時間的監(jiān)控,實際業(yè)務(wù)運行中若出現(xiàn)明顯、頻繁的慢查詢或慢寫入,則我們需要格外地注意,及時定位問題出現(xiàn)的原因。

這時候,如果數(shù)據(jù)庫自身能夠提供實例上語句執(zhí)行時間的統(tǒng)計,做到可宏觀(能夠觀察整體執(zhí)行時間分布情況)、可微觀(能夠定位執(zhí)行慢的語句),自然能起到事半功倍的效用。

早在MySQL 8.0以前的版本中,performance_schema表就已經(jīng)有多個Statement Summary表,用于記錄當(dāng)前或近期的語句執(zhí)行事件。

mysql> show tables from performance_schema like 'events_statements_summary%';+-----------------------------------------------------------+| Tables_in_performance_schema (events_statements_summary%) |+-----------------------------------------------------------+| events_statements_summary_by_account_by_event_name        || events_statements_summary_by_digest                       || events_statements_summary_by_host_by_event_name           || events_statements_summary_by_program                      || events_statements_summary_by_thread_by_event_name         || events_statements_summary_by_user_by_event_name           || events_statements_summary_global_by_event_name            |+-----------------------------------------------------------+7 rows in set (0.00 sec)

按照對事件的grouping策略的不同,這些語句事件summary表一共劃分成了7個。其中events_statements_summary_by_digest按照語句的digest值語句所操作的schema名這兩個元素來分組存儲數(shù)據(jù),表中的每一行數(shù)據(jù)總結(jié)了一個schema上執(zhí)行的一組相同性質(zhì)(具體值可以不同)的語句的執(zhí)行信息。

其中,語句的digest指的是一個語句去掉語句內(nèi)某些具體的值(如插入表中的具體值)、進行模板化之后的語句,再經(jīng)過哈希算法得到的唯一值。例如,某個語句INSERT INTO d1.t1 VALUES(1024, "hello world")先經(jīng)過模板化,得到模板語句INSERT INTO d1.t1 VALUES(...),然后經(jīng)過哈希得到一個唯一的digest值。

舉個例子,我向test庫中的texts表插入了四行數(shù)據(jù):

mysql> use test;Database changedmysql> insert into texts values("hello");Query OK, 1 row affected (0.00 sec)mysql> insert into texts values("hi");Query OK, 1 row affected (0.01 sec)mysql> insert into texts values("how are you");Query OK, 1 row affected (0.01 sec)mysql> insert into texts values("goodbye");Query OK, 1 row affected (0.01 sec)

然后可以在表中找到上面四條INSERT執(zhí)行的統(tǒng)計數(shù)據(jù):

mysql> select * from performance_schema.events_statements_summary_by_digest where schema_name='test'\G...*************************** 4. row ***************************                SCHEMA_NAME: test                     DIGEST: 894869beecac725bf46aa9c43778d476252a5b1c85ecd0139287ab15b2bd3c0b                DIGEST_TEXT: INSERT INTO `texts` VALUES (?)    # 模板化后的語句                 COUNT_STAR: 4            # 屬于該digest的實際語句執(zhí)行數(shù)量             SUM_TIMER_WAIT: 29030259000  # 語句執(zhí)行時間總和             MIN_TIMER_WAIT: 6432990000   # 語句執(zhí)行時間最小值             AVG_TIMER_WAIT: 7257564000   # 語句執(zhí)行時間平均值             MAX_TIMER_WAIT: 8168797000   # 語句執(zhí)行時間最大值              SUM_LOCK_TIME: 495000000                 SUM_ERRORS: 0               SUM_WARNINGS: 0          SUM_ROWS_AFFECTED: 4              SUM_ROWS_SENT: 0          SUM_ROWS_EXAMINED: 0SUM_CREATED_TMP_DISK_TABLES: 0     SUM_CREATED_TMP_TABLES: 0       SUM_SELECT_FULL_JOIN: 0 SUM_SELECT_FULL_RANGE_JOIN: 0           SUM_SELECT_RANGE: 0     SUM_SELECT_RANGE_CHECK: 0            SUM_SELECT_SCAN: 0      SUM_SORT_MERGE_PASSES: 0             SUM_SORT_RANGE: 0              SUM_SORT_ROWS: 0              SUM_SORT_SCAN: 0          SUM_NO_INDEX_USED: 0     SUM_NO_GOOD_INDEX_USED: 0                 FIRST_SEEN: 2020-07-09 16:08:33.329338 # 屬于該digest的已執(zhí)行語句中,第一條執(zhí)行的時刻                  LAST_SEEN: 2020-07-09 16:08:47.193867 # 屬于該digest的已執(zhí)行語句中,最后一條執(zhí)行的時刻                QUANTILE_95: 8317637711   # 95%的同digest語句執(zhí)行時間小于這個值                QUANTILE_99: 8317637711   # 99%的同digest語句執(zhí)行時間小于這個值               QUANTILE_999: 8317637711   # 99.9%的同digest語句執(zhí)行時間小于這個值          QUERY_SAMPLE_TEXT: insert into texts values("hi")    # 屬于該digest的已執(zhí)行語句中的某個樣本          QUERY_SAMPLE_SEEN: 2020-07-09 16:08:37.642837        # 樣本執(zhí)行的時刻    QUERY_SAMPLE_TIMER_WAIT: 8168797000                        # 樣本執(zhí)行耗時4 rows in set (0.00 sec)

這里COUNT_STAR列指出了執(zhí)行的同一digest的語句有4個,與我上面的實際插入操作相符。緊跟其后的是幾個我們比較關(guān)注的統(tǒng)計數(shù)據(jù),SUM_TIMER_WAIT代表這4條插入執(zhí)行的總耗時是29030259000 ps,也就是大約29.03 ms;MIN_TIMER_WAIT代表這4條插入中耗時最短的一條花了6.43 ms;AVG_TIMER_WAIT代表這4條插入中平均耗時7.25 ms;MAX_TIMER_WAIT代表這4條插入中耗時最長的一條花了8.16 ms。

三個QUANTILE_xx字段也是我們比較關(guān)注的數(shù)據(jù)之一。上例中QUANTILE_95值為8317637711,表示95%的同digest語句執(zhí)行耗時在8.31 ms以內(nèi);

以此類推,下面的QUANTILE_99和QUANTILE_999分別表示99%和99.9%。

這里需要注意,最后三列是MySQL 8.0給該表新增的三個字段,其給出了上面執(zhí)行的4條插入中的一個樣本(sample),并提供了這個樣本的(最后一次)執(zhí)行時間與耗時兩個信息。

PartⅡ MySQL 8.0 histogram 介紹

上面提到的summary表中,比較籠統(tǒng)的記錄了語句執(zhí)行的耗時等信息,包含了最大值、最小值、平均值等,但是這些信息可能不夠,不能直觀地看到同一語句的用時分布情況。

在MySQL 8.0中,performance_schema中新增了兩個histogram表使得語句執(zhí)行時間的統(tǒng)計信息更加豐富,分別是events_statements_histogram_by_digesevents_statements_histogram_global

Histogram的中文意指“直方圖”,顧名思義,這兩個表所提供的是對語句執(zhí)行事件執(zhí)行時間的直方圖形式的統(tǒng)計記錄。

2.1 events_statements_histogram_by_digest介紹

在events_statements_histogram_by_digest中,依照語句所操作的schema名與digest值來標識行,使用上面實例的4條插入的digest值在events_statements_histogram_by_digest查找直方圖統(tǒng)計數(shù)據(jù),可以得到:
mysql> select * from performance_schema.events_statements_histogram_by_digest     -> where DIGEST='894869beecac725bf46aa9c43778d476252a5b1c85ecd0139287ab15b2bd3c0b'    -> and SCHEMA_NAME='test' and COUNT_BUCKET>0\G*************************** 1. row ***************************           SCHEMA_NAME: test                DIGEST: 894869beecac725bf46aa9c43778d476252a5b1c85ecd0139287ab15b2bd3c0b         BUCKET_NUMBER: 141      BUCKET_TIMER_LOW: 6309573444     BUCKET_TIMER_HIGH: 6606934480          COUNT_BUCKET: 1COUNT_BUCKET_AND_LOWER: 1       BUCKET_QUANTILE: 0.250000*************************** 2. row ***************************           SCHEMA_NAME: test                DIGEST: 894869beecac725bf46aa9c43778d476252a5b1c85ecd0139287ab15b2bd3c0b         BUCKET_NUMBER: 143      BUCKET_TIMER_LOW: 6918309709     BUCKET_TIMER_HIGH: 7244359600          COUNT_BUCKET: 1COUNT_BUCKET_AND_LOWER: 2       BUCKET_QUANTILE: 0.500000*************************** 3. row ***************************           SCHEMA_NAME: test                DIGEST: 894869beecac725bf46aa9c43778d476252a5b1c85ecd0139287ab15b2bd3c0b         BUCKET_NUMBER: 144      BUCKET_TIMER_LOW: 7244359600     BUCKET_TIMER_HIGH: 7585775750          COUNT_BUCKET: 1COUNT_BUCKET_AND_LOWER: 3       BUCKET_QUANTILE: 0.750000*************************** 4. row ***************************           SCHEMA_NAME: test                DIGEST: 894869beecac725bf46aa9c43778d476252a5b1c85ecd0139287ab15b2bd3c0b         BUCKET_NUMBER: 146      BUCKET_TIMER_LOW: 7943282347     BUCKET_TIMER_HIGH: 8317637711          COUNT_BUCKET: 1COUNT_BUCKET_AND_LOWER: 4       BUCKET_QUANTILE: 1.0000004 rows in set (0.00 sec)

在events_statements_histogram_by_digest中,同一digest值的語句事件按照執(zhí)行時間大小被納入不同的bucket中,BUCKET_TIMER_LOW字段表示該bucket內(nèi)語句事件的執(zhí)行時間下限,BUCKET_TIMER_HIGH字段表示上限,如上面我所執(zhí)行的4條插入,其中一條的執(zhí)行時間在6309573444 ps = 6.30 ms到6606934480 ps = 6.60 ms之間,因此該語句事件被收入BUCKET_NUMBER(bucket的標識數(shù)字)為141的bucket中。

COUNT_BUCKET字段的數(shù)值表示有多少語句事件被收入該bucket中,在本例中,4條插入的執(zhí)行時間差距比較大,因此被收入了4個不同的bucket中,并且我在查詢的時候指定了篩選出COUNT_BUCKET大于0的結(jié)果,因此所以“空bucket”的數(shù)據(jù)都沒有展示。COUNT_BUCKET_AND_LOWER表示有多少語句事件的執(zhí)行時間比該bucket的上限小,BUCKET_QUANTILE則表示有百分之多少的語句事件的執(zhí)行時間比該bucket的上限小,在本例中,第144個bucket(在第3行)的執(zhí)行時間上限是7.58 ms,有4條插入中有3條的執(zhí)行時間小于這個值,也就是75%的執(zhí)行時間小于這個值。

還可以通過以下方式的查詢,直觀地展示該digest語句的執(zhí)行時間分布:
mysql> SELECT DIGEST_TEXT,    -> CONCAT('<',ROUND(BUCKET_TIMER_HIGH/1000000000,2),'ms') as 'TIME',    -> CONCAT(RPAD('',ROUND(BUCKET_QUANTILE*100/4),'*'),ROUND(BUCKET_QUANTILE*100,2),"%") QUANTILE    -> FROM events_statements_histogram_by_digest t1    -> JOIN events_statements_summary_by_digest t2    -> ON t2.DIGEST = t1.DIGEST    -> WHERE COUNT_BUCKET >0 and t1.DIGEST='894869beecac725bf46aa9c43778d476252a5b1c85ecd0139287ab15b2bd3c0b'    -> ORDER BY t1.DIGEST, BUCKET_TIMER_HIGH DESC;+--------------------------------+---------+----------------------------------+| DIGEST_TEXT                    | TIME    | QUANTILE                         |+--------------------------------+---------+----------------------------------+| INSERT INTO `texts` VALUES (?) | <8.32ms | *************************100.00% || INSERT INTO `texts` VALUES (?) | <7.59ms | *******************75.00%        || INSERT INTO `texts` VALUES (?) | <7.24ms | ************50.00%               || INSERT INTO `texts` VALUES (?) | <6.61ms | ******25.00%                     |+--------------------------------+---------+----------------------------------+4 rows in set (0.00 sec)

2.2 events_statements_histogram_global介紹

在events_statements_histogram_global表中,不再按照schema名或語句事件的digest來標識行,而是把所有的語句事件不做任何區(qū)分,直接扔入代表不同執(zhí)行時間區(qū)間的bucket中,因此得到的將是對語句事件執(zhí)行時間的一個宏觀的統(tǒng)計數(shù)據(jù):

mysql> show create table performance_schema.events_statements_histogram_global\G*************************** 1. row ***************************       Table: events_statements_histogram_globalCreate Table: CREATE TABLE `events_statements_histogram_global` (  `BUCKET_NUMBER` int(10) unsigned NOT NULL,  `BUCKET_TIMER_LOW` bigint(20) unsigned NOT NULL,  `BUCKET_TIMER_HIGH` bigint(20) unsigned NOT NULL,  `COUNT_BUCKET` bigint(20) unsigned NOT NULL,  `COUNT_BUCKET_AND_LOWER` bigint(20) unsigned NOT NULL,  `BUCKET_QUANTILE` double(7,6) NOT NULL,  PRIMARY KEY (`BUCKET_NUMBER`)) ENGINE=PERFORMANCE_SCHEMA DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci1 row in set (0.00 sec)

在Percona 5.7中,有個QUERY_RESPONSE_TIME插件,用一個query_response_time表來統(tǒng)計所有語句的執(zhí)行時間,得到執(zhí)行時間的分布情況:

mysql> select * from information_schema.query_response_time where COUNT>0;+----------------+-------+----------------+| TIME           | COUNT | TOTAL          |+----------------+-------+----------------+|       0.000015 |     6 |       0.000052 ||       0.000061 |     8 |       0.000367 ||       0.000122 |    20 |       0.001775 ||       0.000244 |     8 |       0.001438 ||       0.000488 |     8 |       0.002514 ||       0.000976 |     4 |       0.002079 ||       0.001953 |     4 |       0.004707 ||       0.003906 |     1 |       0.002767 ||       0.007812 |     3 |       0.020409 ||       0.015625 |     6 |       0.066448 ||       0.031250 |     3 |       0.057138 ||       0.062500 |     2 |       0.097577 ||       0.125000 |     1 |       0.079703 ||       8.000000 |     1 |       5.000150 |+----------------+-------+----------------+14 rows in set (0.00 sec)
在MySQL 8.0中,借助原生的全局histogram表,通過指定的查詢,也可以得到類似形式的統(tǒng)計數(shù)據(jù):
mysql> select CONCAT(BUCKET_TIMER_HIGH/1000000000, " ms") TIME, COUNT_BUCKET COUNT    -> from performance_schema.events_statements_histogram_global where COUNT_BUCKET>0;+------------+-------+| TIME       | COUNT |+------------+-------+|0.0437 ms  |     1 || 0.0631 ms  |     1 ||0.0692 ms  |     2 || 0.1202 ms  |     2 ||0.1318 ms  |     2 || 0.1445 ms  |     2 ||0.1738 ms  |     1 || 0.2399 ms  |     1 ||0.3020 ms  |     1 || 0.4786 ms  |     1 ||0.5012 ms  |     2 || 0.5248 ms  |     7 ||0.5495 ms  |     8 || 0.5754 ms  |     6 ||0.6026 ms  |     5 || 0.6310 ms  |     9 ||0.6607 ms  |     4 || 0.6918 ms  |     9 ||0.7244 ms  |     4 || 0.7586 ms  |     3 ||0.7943 ms  |     7 || 0.8318 ms  |     3 ||0.8710 ms  |     2 || 0.9120 ms  |     1 ||0.9550 ms  |     4 || 1.0000 ms  |     3 ||1.0471 ms  |     2 || 1.0965 ms  |     1 ||1.1482 ms  |     2 || 1.2023 ms  |     6 ||1.2589 ms  |     6 || 1.3183 ms  |     2 ||1.4454 ms  |     1 || 1.5136 ms  |     1 ||1.6596 ms  |     3 || 1.7378 ms  |     3 ||2.1878 ms  |     1 || 2.2909 ms  |     1 ||2.6303 ms  |     2 || 3.0200 ms  |     1 ||3.1623 ms  |     1 || 5.7544 ms  |     1 ||6.6069 ms  |     1 || 7.2444 ms  |     1 ||7.5858 ms  |     1 || 8.3176 ms  |     1 ||10.9648 ms |     1 || 41.6869 ms |     1 |+------------+-------+48 rows in set (0.00 sec)

由于MySQL 8.0所提供的histogram表既可以宏觀統(tǒng)計語句執(zhí)行時間,又可以具體定位某個語句的執(zhí)行時間分布,功能上已經(jīng)比Percona的QUERY_RESPONSE_TIME插件更加豐富,因此在Percona 8.0中這一插件也被移除。

PartⅢ 二次開發(fā)改進

3.1 原生MySQL的局限

原生MySQL 8.0中的histogram表實現(xiàn)雖然功能不錯,但是也存在著一些局限。
首先是histogram中bucket的數(shù)量,在events_statements_histogram_global表中,bucket的數(shù)量是450:
mysql> select count(*) from performance_schema.events_statements_histogram_global;+----------+| count(*) |+----------+|      450 |+----------+1 row in set (0.00 sec)

在events_statements_histogram_by_digest中,每條digest所對應(yīng)的histogram的bucket數(shù)量也是450,則mysqld記錄了n條digest,events_statements_histogram_by_digest表中就有n * 450行數(shù)據(jù):

mysql> select count(*) from performance_schema.events_statements_histogram_by_digest;+----------+| count(*) |+----------+|     8100 |+----------+1 row in set (0.00 sec)# 注:此時服務(wù)器記錄有18條digest記錄

接著我通過SHOW VARIABLES查找是否存在某個變量可以調(diào)整bucket的數(shù)量,沒有找到相關(guān)的結(jié)果,進一步查看源碼,發(fā)現(xiàn)這一部分是用一個宏定義硬編碼了bucket的數(shù)量:

/**
  @file storage/perfschema/pfs_histogram.h
*/

/** Number of buckets used in histograms. */
#define NUMBER_OF_BUCKETS 450

并且針對每個bucket所代表的時間區(qū)間,硬編碼了一個最小時間上限和bucket增長指數(shù):

/**
  @file storage/perfschema/pfs_histogram.cc
*/

/**
  Histogram base bucket timer, in picoseconds.
  Currently defined as 10 micro second.
  
  @解釋:最小的bucket(第1個bucket)的時間上限,值為10ms。
*/
#define BUCKET_BASE_TIMER (10 * 1000 * 1000)

/**
  Bucket factor.
  histogram_timer[i+1] = BUCKET_BASE_FACTOR * histogram_timer[i]
  The value is chosen so that BUCKET_BASE_FACTOR ^ 50 = 10,
  which corresponds to a 4.7 percent increase for each bucket,
  or a power of 10 increase for 50 buckets.

  @解釋:每個bucket相比前一個bucket的時間上限增長指數(shù)。
  例,
  第1個bucket的時間上限是10ms,則對于第2個bucket:
  時間上限是10*1.0471285480508996ms,約為10.47ms;時間下限則是前一個bucket的上限值,也就是10ms。
*/
#define BUCKET_BASE_FACTOR 1.0471285480508996

這一部分硬編碼存在如下問題:

不同的業(yè)務(wù)的讀寫需求不一致,所需要的執(zhí)行時間監(jiān)測粒度也盡不相同。MySQL默認強制劃分成450個bucket,bucket的增長指數(shù)是1.047,雖然劃分得非常精細,但是可能實際業(yè)務(wù)并不需要這么精細的監(jiān)測粒度,也許我們只需要幾十個bucket,并且將10ms的執(zhí)行時間與20ms的執(zhí)行時間一視同仁,算進一個bucket里。因此如果bucket的數(shù)量與bucket的增長指數(shù)可以視作變量人為調(diào)整,可以使得histogram的統(tǒng)計更加符合實際業(yè)務(wù)的需求。

就如在前面所提到的,events_statements_histogram_by_digest表中的行數(shù)是digest記錄的數(shù)量與450的乘積,不管實際的語句事件執(zhí)行時間有沒有落到某個bucket里,也就是說即便某個bucket的count值是空的,其也在表中占據(jù)一行。假如某一digest語句事件執(zhí)行時間的分布比較均勻,使得空bucket比較少,那倒沒什么,但是實際情況通常是某一digest的語句事件的執(zhí)行時間集中分布在某個小范圍內(nèi),可能最多占幾十個bucket,剩下幾百個bucket可能一直不會用到,使得絕大部分的行是浪費的,我們知道performance_schema中的表都是內(nèi)存表,數(shù)據(jù)存放在內(nèi)存中,這也就直接導(dǎo)致服務(wù)器的內(nèi)存被浪費。

為了驗證第二個問題,我進一步查看源碼。首先在pfs_digest.h中,定義了PFS_statements_digest_stat類,解讀源碼可以發(fā)現(xiàn)一個該類的對象對應(yīng)events_statements_summary_by_digest表(注意是summary表)中的一條記錄,包含了我們前面所見到的digest值、sample與第一次和最后一次執(zhí)行時刻等信息(在下面代碼中忽略)。在里面我們可以看到一個PFS_histogram對象的成員,這里猜測其應(yīng)當(dāng)是一條digest記錄所對應(yīng)的histogram。

/** A statement digest stat record. */struct PFS_ALIGNED PFS_statements_digest_stat {  /* 其他成員變量與成員函數(shù)在此省略 */  // FIXME : allocate in separate buffer  PFS_histogram m_histogram; /* 一個digest所對應(yīng)的histogram */};

接著查看PFS_histogram類的定義,其唯一的成員是一個長度為宏定義NUMBER_OF_BUCKETS(值為450)的數(shù)組,不難看出這個成員就是histogram中bucket的計數(shù)數(shù)組。假設(shè)某個digest值的語句執(zhí)行時間為10.1 ms,這一時間對應(yīng)的bucket應(yīng)當(dāng)是第2個bucket,那么該digest的histogram中對應(yīng)的bucket計數(shù)應(yīng)該加1,也就是m_bucket[1]++,實際代碼中通過調(diào)用increment_bucket公共接口進行計數(shù)累加。

struct PFS_histogram { public:  void reset();  void increment_bucket(uint bucket_index) { m_bucket[bucket_index]++; }  ulonglong read_bucket(uint bucket_index) { return m_bucket[bucket_index]; } private:  std::atomic<ulonglong> m_bucket[NUMBER_OF_BUCKETS];};

上面的代碼可以看到,1條digest記錄包含了1個屬于該digest的histogram,這個histogram中有一個長度為450的無符號長整數(shù)數(shù)組作bucket計數(shù)用途。那么所有digest記錄是怎么實際存儲在內(nèi)存中的呢?我們接著查看源碼,可以在pfs_digest.cc中找到一個PFS_statements_digest_stat對象的動態(tài)數(shù)組,用于存放所有的digest記錄:

/** EVENTS_STATEMENTS_SUMMARY_BY_DIGEST buffer. */PFS_statements_digest_stat *statements_digest_stat_array = NULL;

這個動態(tài)數(shù)組的實際內(nèi)存分配代碼如下:

statements_digest_stat_array = PFS_MALLOC_ARRAY(    &builtin_memory_digest, digest_max, sizeof(PFS_statements_digest_stat),    PFS_statements_digest_stat, MYF(MY_ZEROFILL));/*   @注:以上代碼近似于   statements_digest_stat_array = malloc(digest_max * sizeof(PFS_statements_digest_stat));*/

可以看到PFS_statements_digest_stat的長度由變量digest_max決定,其代表服務(wù)器允許的最大digest記錄數(shù)量,也就是events_statements_summary_by_digest表的最大行數(shù),而digest_max的值由global變量performance_schema_digests_size決定,其默認值為10000,最大允許值為1024 * 1024。

mysql> show variables like 'performance_schema_digests_size';+---------------------------------+-------+| Variable_name                   | Value |+---------------------------------+-------+| performance_schema_digests_size | 10000 |+---------------------------------+-------+1 row in set (0.00 sec)

結(jié)合以上源碼我們可以得出結(jié)論,假設(shè)各個histogram中的450個bucket最多只有32個是實際需要用到的,在performance_schema_digests_size取默認值10000的情況下,由于所有digest記錄的內(nèi)存是預(yù)先分配好的,會造成10000 * (450 - 32) * sizeof(ulonglong) = 31.89 MB的內(nèi)存浪費;而在performance_schema_digests_size取最大允許值時,更是會造成1024 * 1024 * (450 - 32) * sizeof(ulonglong) = 3344 MB的內(nèi)存浪費。

3.2 所作改進

針對這兩個問題,我分成兩步進行改進。

首先在第一步,我們引入兩個只讀global的變量performance_schema_events_statements_histogram_bucket_number和performance_schema_events_statements_histogram_base_factor,分別用作histogram中bucket的數(shù)量(默認值為32)與每個bucket時間上限的增長指數(shù)(默認值為2.0),取代原生版本中的硬編碼:

mysql> show variables like 'performance_schema_events_statements_histogram%';+--------------------------------------------------------------+----------+| Variable_name                                                | Value    |+--------------------------------------------------------------+----------+| performance_schema_events_statements_histogram_base_factor   | 2.000000 || performance_schema_events_statements_histogram_bucket_number | 32       |+--------------------------------------------------------------+----------+2 rows in set (0.00 sec)

用戶若需要采用不同的bucket數(shù)量與增長指數(shù),只需在啟動mysqld時指定變量值即可:

$ mysqld --performance_schema_events_statements_histogram_bucket_number=64 --performance_schema_events_statements_histogram_base_factor=1.5

經(jīng)過這個改進,用戶可以靈活地調(diào)整histogram的統(tǒng)計粒度,使之更符合運維管理的特定化需求。采用默認值的實際效果如下:

mysql> insert into testTable values('first');Query OK, 1 row affected (0.00 sec)mysql> insert into testTable values('second');Query OK, 1 row affected (0.01 sec)mysql> insert into testTable values('third');Query OK, 1 row affected (0.01 sec)mysql> insert into testTable values('fourth');Query OK, 1 row affected (0.01 sec)mysql> insert into testTable values('fifth');Query OK, 1 row affected (0.02 sec)mysql> select DIGEST, DIGEST_TEXT from performance_schema.events_statements_summary_by_digest where DIGEST_TEXT like 'INSERT%';+------------------------------------------------------------------+------------------------------------+| DIGEST                                                           | DIGEST_TEXT                        |+------------------------------------------------------------------+------------------------------------+| 9cb9e9a5b12f41fb4e28ca6c2ed37843a47222a8903dc4f6b6ceb35bb8445012 | INSERT INTO `testTable` VALUES (?) |+------------------------------------------------------------------+------------------------------------+1 row in set (0.00 sec)mysql> select * from performance_schema.events_statements_histogram_by_digest where DIGEST='9cb9e9a5b12f41fb4e28ca6c2ed37843a47222a8903dc4f6b6ceb35bb8445012'\G...*************************** 11. row ***************************           SCHEMA_NAME: testdb                DIGEST: 9cb9e9a5b12f41fb4e28ca6c2ed37843a47222a8903dc4f6b6ceb35bb8445012         BUCKET_NUMBER: 10      BUCKET_TIMER_LOW: 5120000000     BUCKET_TIMER_HIGH: 10240000000          COUNT_BUCKET: 3COUNT_BUCKET_AND_LOWER: 3       BUCKET_QUANTILE: 0.600000*************************** 12. row ***************************           SCHEMA_NAME: testdb                DIGEST: 9cb9e9a5b12f41fb4e28ca6c2ed37843a47222a8903dc4f6b6ceb35bb8445012         BUCKET_NUMBER: 11      BUCKET_TIMER_LOW: 10240000000     BUCKET_TIMER_HIGH: 20480000000          COUNT_BUCKET: 2COUNT_BUCKET_AND_LOWER: 5       BUCKET_QUANTILE: 1.000000...32 rows in set (0.00 sec)
針對內(nèi)存浪費的問題,我重寫了PFS_histogram的類定義,用動態(tài)數(shù)組取代了原生版本的Raw數(shù)組,相關(guān)細節(jié)不在此贅述。實際運行中,performance_schema_digests_size變量選用最大允許值1024 * 1024 = 1048576

到此,關(guān)于“怎么解析與優(yōu)化MySQL 8.0 PFS histogram”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI