mysql 系统库(二) —— 数据库对象信息、统计信息、优化器成本记录表

一、 数据库对象信息记录表

这类表的功能基本都已被information_schema下同名表取代,本节只做一些简单介绍。

1. plugin表

该表提供查询自定义安装的插件信息(非系统默认启用的插件),该表的功能已经被information_schema.plugins表取代。

root@localhost : mysql 01:00:20> select * from plugin;
+------------------------------------------+-----------------------+
| name                                     | dl                    |
+------------------------------------------+-----------------------+
| CONNECTION_CONTROL                       | connection_control.so |
| CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS | connection_control.so |
+------------------------------------------+-----------------------+
2 rows in set (0.00 sec)

表字段含义

  • name:自定义安装插件时指定的插件名称。

  • dl:自定义安装的插件so库名称。

2. proc表

记录存储过程与函数相关信息,类似information_schema.routines表,但后者更加详细。

select * from proc limit 1\G;

*************************** 1. row ***************************
                  db: sys
                name: extract_schema_from_file_name
                type: FUNCTION
       specific_name: extract_schema_from_file_name
            language: SQL
     sql_data_access: NO_SQL
    is_deterministic: YES
       security_type: INVOKER
          param_list:  path VARCHAR(512) 
             returns: varchar(64) CHARSET utf8
                body: BEGIN RETURN LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(REPLACE(path, '\\', '/'), '/', -2), '/', 1), 64); END
             definer: mysql.sys@localhost
             created: 2017-07-01 14:31:32
            modified: 2017-07-01 14:31:32
            sql_mode: 
             comment: 
 Description
 ......
character_set_client: utf8
collation_connection: utf8_general_ci
        db_collation: utf8_general_ci
           body_utf8: BEGIN RETURN LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(REPLACE(path, '\', '/'), '/', -2), '/', 1), 64); END
1 row in set (0.01 sec)

3. event表

提供查询计划任务相关的事件信息,类似information_schema.events表,但后者更加详细。

root@localhost : mysql 01:02:41> select * from event limit 1\G;
*************************** 1. row ***************************
                  db: sbtest
                name: test_event
                body: BEGIN
insert into test_table select max(id) from sbtest1;
      END
             definer: root@%
          execute_at: NULL
      interval_value: 1
      interval_field: DAY
             created: 2018-01-21 17:05:37
            modified: 2018-01-21 17:08:56
       last_executed: NULL
              starts: 2018-01-21 09:05:37
                ends: NULL
              status: ENABLED
       on_completion: DROP
            sql_mode: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
             comment: 每天统计sbtest1表中的最大自增值
          originator: 3306111
           time_zone: +08:00
character_set_client: utf8
collation_connection: utf8_general_ci
        db_collation: utf8_bin
           body_utf8: BEGIN
insert into test_table select max(id) from sbtest1;
      END
1 row in set (0.00 sec)

4、func

记录函数审计与防火墙相关信息,类似information_schema.routines表,但后者更加详细。另外该表还专用于记录从so插件库中安装的函数信息。

select * from func;
+--------------------------------+-----+--------------+-----------+
| name | ret | dl | type |
+--------------------------------+-----+--------------+-----------+
| audit_log_filter_flush | 0 | audit_log.so | function |
| audit_log_filter_remove_user | 0 | audit_log.so | function |
| audit_log_filter_set_user | 0 | audit_log.so | function |
| audit_log_filter_remove_filter | 0 | audit_log.so | function |
| audit_log_filter_set_filter | 0 | audit_log.so | function |
| set_firewall_mode | 0 | firewall.so | function |
| normalize_statement | 0 | firewall.so | function |
| mysql_firewall_flush_status | 0 | firewall.so | function |
| read_firewall_whitelist | 0 | firewall.so | aggregate |
| read_firewall_users | 0 | firewall.so | aggregate |
+--------------------------------+-----+--------------+-----------+
10 rows in set (0.00 sec)

二、 统计信息记录表

1. 统计信息概述

  • 统计信息持久化

统计信息持久化功能将内存中的统计信息存储到磁盘,数据库重启时可以快速重新读入而不用重新执行统计,使得查询优化器可以利用这些持久化的统计信息准确地选择执行计划。持久化统计信息存储在mysql.innodb_table_stats和mysql.innodb_index_stats表中,前者存放表结构、数据行相关统计信息,后者存放索引相关统计信息。

当设置innodb_stats_persistent = ON(默认)或者建表时使用了STATS_PERSISTENT = 1选项,表示开启统计信息的持久化功能。前者为全局开启,后者为单表开启。要单独关闭某个表的持久化统计信息功能,执行 ALTER TABLE tbl_name STATS_PERSISTENT = 0; 。

 

  • 统计信息自动重新计算

innodb_stats_auto_recalc系统变量控制是否启用统计信息的自动计算功能,默认开启,表中的数据量变更超过10%时会触发统计信息自动计算功能。也可以在CREATE TABLE或ALTER TABLE语句中使用STATS_AUTO_RECALC子句为单表配置统计信息自动重新计算功能。

自动重新计算在后台运行,即使启用了innodb_stats_auto_recalc系统变量,当表中的数据DML操作超过10%之后,统计信息也可能不会立即重新计算,某些情况下可能会延迟几秒钟,如果需要统计信息精确,可以手动执行ANALYZE TABLE语句。

当某表添加新的索引时,无论innodb_stats_auto_recalc的值如何,都会触发重新计算索引统计信息并将其添加到innodb_index_stats表中。要想在添加索引时将相关的统计信息同时更新到mysql.innodb_table_stats表中,还是需要启用innodb_stats_auto_recalc或者修改表的innodb_stats_auto_recalc建表选项,或者对表执行ANALYZE TABLE语句。

 

  • InnoDB优化器统计信息采样页数

优化器使用索引键值相关统计信息来计算索引选择度,进而选择合适的索引。这些统计信息是如何得来的呢?例如,当执行ANALYZE TABLE时,InnoDB会从表中的每个索引中抽取随机页面来估计索引的基数(随机采样),采样页的数量由系统参数innodb_stats_persistent_sample_pages决定,默认为20,该变量为动态变量。通常情况下不需要修改。增大该变量置可能导致每次采样时间变长,但如果确定默认的采样数量会导致索引统计信息不精确,可以尝试逐步增加该系统变量值,直到具有足够精确的统计信息为止。统计信息是否精确可以通过SELECT DISTINCT(index_name)返回值与mysql.innodb_index_stats表中提供的估计值进行对比检查。

 

使用统计信息相关选项建表示例:

CREATE TABLE `t1` (
`id` int(8) NOT NULL auto_increment,
`data` varchar(255),
`date` datetime,
PRIMARY KEY (`id`),
INDEX `DATE_IX` (`date`)
) ENGINE=InnoDB,
  STATS_PERSISTENT=1, -- 统计信息持久化
  STATS_AUTO_RECALC=1, -- 统计信息自动重新计算
  STATS_SAMPLE_PAGES=25; -- 设置估算索引列的基数和其他统计数据时要抽样的索引页数
  • 如何配置在持久化统计信息的计算中包括删除标记的记录

默认情况下,InnoDB在计算统计信息时会读取未提交的数据。对于从表中执行删除行操作的未提交事务,InnoDB在估算行和索引统计信息时会忽略这些被打上删除标记的记录,这可能会导致对该表执行并行查询的其他事务的执行计划并不精确。为了避免这种情况,可以启用系统参数innodb_stats_include_delete_marked来确保InnoDB在计算持久化统计信息时包含被打上删除标记的记录。该参数为全局变量,不能单独设置某个表,并且在5.7.16中才引入。

  • 注意事项

统计信息持久化依赖于mysql库下的innodb_table_stats和innodb_index_stats表。这些表在安装、升级和源代码构建过程中会自动设置。

innodb_table_stats和innodb_index_stats表是普通表,可以手动执行更新。通过手动更新统计信息的功能,可以强制执行特定的查询优化计划或测试备选计划,而无需修改数据库。如果手动更新统计信息,需要执行语句FLUSH TABLE tbl_name命令使MySQL重新加载更新后的统计信息。

持久性统计信息被视为本地信息,因为它们与实例自身相关。因此innodb_table_stats和innodb_index_stats表的自动统计信息数据变更不会在主备之间复制。但如果是手动执行ANALYZE TABLE语句来触发统计信息重新计算,ANALYZE TABLE语句本身会在主备架构之间复制,在备库也重新计算统计信息(除非主库操作时设置了set sql_log_bin=0之类的语句关闭了日志记录)。

2. innodb_table_stats

该表提供查询表数据相关的统计信息。

select * from innodb_table_stats where table_name='test'\G;

*************************** 1. row ***************************
           database_name: test
              table_name: test
             last_update: 2018-05-24 20:00:50
                  n_rows: 6
    clustered_index_size: 1
sum_of_other_index_sizes: 2
1 row in set (0.00 sec)

表字段含义:

  • database_name:数据库名。

  • table_name:表名、分区名或子分区名。

  • last_update:表示InnoDB上次更新此统计信息行的时间戳。

  • n_rows:表中的估算数据记录行数。

  • clustered_index_size:主键索引的大小,以页为单位的估算数值。

  • sum_of_other_index_sizes:其他(非主键)索引的总大小,以页为单位的估算数值。

3. innodb_index_stats

该表提供查询索引相关的统计信息。

select * from innodb_index_stats where table_name='test';

+---------------+------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+
| database_name | table_name | index_name | last_update | stat_name | stat_value | sample_size | stat_description |
+---------------+------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+
| test | test | PRIMARY | 2018-05-24 20:00:50 | n_diff_pfx01 | 5 | 1 | a |
| test | test | PRIMARY | 2018-05-24 20:00:50 | n_diff_pfx02 | 6 | 1 | a,b |
| test | test | PRIMARY | 2018-05-24 20:00:50 | n_leaf_pages | 1 | NULL | Number of leaf pages in the index |
| test | test | PRIMARY | 2018-05-24 20:00:50 | size | 1 | NULL | Number of pages in the index |
| test | test | i1 | 2018-05-24 20:00:50 | n_diff_pfx01 | 5 | 1 | c |
| test | test | i1 | 2018-05-24 20:00:50 | n_diff_pfx02 | 5 | 1 | c,d |
| test | test | i1 | 2018-05-24 20:00:50 | n_diff_pfx03 | 6 | 1 | c,d,a |
| test | test | i1 | 2018-05-24 20:00:50 | n_diff_pfx04 | 6 | 1 | c,d,a,b |
| test | test | i1 | 2018-05-24 20:00:50 | n_leaf_pages | 1 | NULL | Number of leaf pages in the index |
| test | test | i1 | 2018-05-24 20:00:50 | size | 1 | NULL | Number of pages in the index |
| test | test | i2uniq | 2018-05-24 20:00:50 | n_diff_pfx01 | 6 | 1 | e |
| test | test | i2uniq | 2018-05-24 20:00:50 | n_diff_pfx02 | 6 | 1 | e,f |
| test | test | i2uniq | 2018-05-24 20:00:50 | n_leaf_pages | 1 | NULL | Number of leaf pages in the index |
| test | test | i2uniq | 2018-05-24 20:00:50 | size | 1 | NULL | Number of pages in the index |
+---------------+------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+
14 rows in set (0.00 sec)

表字段含义:

  • database_name:数据库名称。

  • table_name:表名、分区表名、子分区表名称。

  • index_name:索引名称。

  • last_update:表示InnoDB上次更新此统计信息行的时间戳。

  • stat_name:统计信息名称,其对应的统计信息值保存在stat_value列。

  • stat_value:保存统计信息名称stat_name列对应的统计信息值。

  • sample_size:stat_value列中提供的统计信息估计值的采样页数。

  • stat_description:统计信息名称stat_name列中指定的统计信息的说明信息。

stat_name字段详细解释:

stat_name列可有如下几种值:

  • size:stat_value列值表示索引中的总页数量。

  • n_leaf_pages:stat_value列值显示索引叶子页的数量。

  • n_diff_pfxNN(NN代表数字,例如01,02等):stat_value列值表示索引前导列的唯一值数量。例如当NN为01时,stat_value列值表示索引第一列的唯一值数量;当NN为02时,stat_value列值表示索引的第一和第二列组合的唯一值数量,以此类推。

计算索引大小:

可以使用该表中的索引信息页数结合系统变量innodb_page_size的值来计算索引大小:

SELECT SUM(stat_value) pages, index_name,SUM(stat_value)*@@innodb_page_size size 
FROM mysql.innodb_index_stats 
WHERE table_name='dept_emp' AND stat_name = 'size' 
GROUP BY index_name;                         

+-------+------------+----------+
| pages | index_name | size |
+-------+------------+----------+
| 737 | PRIMARY | 12075008 |
| 353 | dept_no | 5783552 |
| 353 | emp_no | 5783552 |
+-------+------------+----------+
3 rows in set (0.01 sec)

 

三、 优化器成本记录表

1. 优化器成本模型概述

优化器成本模型基于以下两个成本模型表,表中值可修改,用于调节执行计划的决策。

  • server_cost表:MySQL常规操作需要用到的优化器成本估算常量值。
  • engine_cost表:针对特定存储引擎操作需要用到的优化器成本估算常量值。

MySQL启动时会将成本模型表读入内存,在生成执行计划时使用内存中的值。表中指定的任何非NULL成本估算常量值会被优先使用,未指定的使用默认常量值(编译时生成的)。

server_cost和engine_cost表中的成本常量数据仅适用于当前实例,对其的修改不会进行复制同步。修改后仅对新连接生效,对修改前已建立的连接不生效。

下面对这两张表进行详细说明。

 2. server_cost

该表提供查询MySQL常规操作需要使用到的优化器成本估算常量值。

select * from server_cost;

+------------------------------+------------+---------------------+---------+
| cost_name                    | cost_value | last_update         | comment |
+------------------------------+------------+---------------------+---------+
| disk_temptable_create_cost   |       NULL | 2017-07-01 14:31:32 | NULL    |
| disk_temptable_row_cost      |       NULL | 2017-07-01 14:31:32 | NULL    |
| key_compare_cost             |       NULL | 2017-07-01 14:31:32 | NULL    |
| memory_temptable_create_cost |       NULL | 2017-07-01 14:31:32 | NULL    |
| memory_temptable_row_cost    |       NULL | 2017-07-01 14:31:32 | NULL    |
| row_evaluate_cost            |       NULL | 2017-07-01 14:31:32 | NULL    |
+------------------------------+------------+---------------------+---------+
6 rows in set (0.00 sec)

表字段含义:

  • cost_name:成本估算变量名称,不区分大小写。如果MySQL在读取此表时未识别成本名称,会向错误日志写入警告。

  • cost_value:成本估算变量值。如果该值不为NULL,MySQL会直接将其用作成本计算。否则会使用默认估计值(代码内的编译默认值)。如果MySQL在读取此表时发现成本值无效(不正确),会向错误日志写入警告。需要恢复默认值,将此字段设置为NULL,然后执行FLUSH OPTIMIZER_COSTS语句即可。

  • last_update:最后一次更新该行记录的时间。

  • comment:与成本估算变量相关的描述性信息。

表中记录的内容即为Server识别的成本估算常量,如下:

  • disk_temptable_create_cost(默认40.0),disk_temptable_row_cost(默认1.0): 基于磁盘内部临时表的成本估算常量。增加这些值会使查询优化器在进行成本估算时会偏向于更少使用磁盘的内部临时表。

  • key_compare_cost(默认0.1):比较记录的成本常量。增加此值会让查询优化器认为需要进行更多比较操作的执行计划是昂贵的。例如比起使用文件排序会更倾向于利用索引来避免排序。

  • memory_temptable_create_cost(默认2.0),memory_temptable_row_cost(默认0.2):基于MEMORY存储引擎的内部临时表的成本估算常量。增加这些值会增加使用内部内存临时表的成本估计值,使得优化器偏向于更少使用它。

  • row_evaluate_cost(默认值为0.2):评估记录行的成本常量。增加此值会让查询优化器认为需要读取更多行的执行计划是昂贵的,偏向于少使用表扫描

3. engine_cost

该表提供查询针对特定存储引擎操作需要用到的优化器成本估算常量值。

select * from engine_cost;

+-------------+-------------+------------------------+------------+---------------------+---------+
| engine_name | device_type | cost_name              | cost_value | last_update         | comment |
+-------------+-------------+------------------------+------------+---------------------+---------+
| default     |           0 | io_block_read_cost     |       NULL | 2017-07-01 14:31:32 | NULL    |
| default     |           0 | memory_block_read_cost |       NULL | 2017-07-01 14:31:32 | NULL    |
+-------------+-------------+------------------------+------------+---------------------+---------+
2 rows in set (0.00 sec)

表字段含义:

  • ENGINE_NAME:此成本估算常量适用的存储引擎名,不区分大小写。default表示适用于所有存储引擎。如果MySQL在读取此表时未识别引擎名称,则会向错误日志写入警告。

  • device_type: 此成本估算常量适用的设备类型。例如为机械硬盘与固态硬盘指定不同的估算常量值。目前该字段未使用,唯一有效值为0。

  • cost_name、cost_value、last_update、comment:与server_cost表中字段含义相同。

该表中记录的有效成本常量值如下:

  • io_block_read_cost(默认1.0):从磁盘读取索引或数据块的成本。增加此值,读取更多磁盘块的查询计划会被认为更加昂贵。例如与读取较少块的范围扫描相比,表扫描被认为是昂贵的。

  • memory_block_read_cost(默认1.0):与io_block_read_cost类似,表示从内存缓冲区中读取索引或数据块的估算常量。

如果io_block_read_cost和memory_block_read_cost值不同,相同查询可能会在两次运行时执行计划发生变化。

更改io_block_read_cost和memory_block_read_cost参数可能会收益。例如在其他条件都相同的情况下,将io_block_read_cost值设置为大于memory_block_read_cost的值会使优化程序更倾向走在内存中查询数据的查询计划。

 

修改io_block_read_cost的示例如下:

-- update已有的常量值
UPDATE mysql.engine_cost SET cost_value = 2.0 WHERE cost_name = 'io_block_read_cost';
FLUSH OPTIMIZER_COSTS;

-- 为innodb引擎单独插入一行常量值
INSERT INTO mysql.engine_cost VALUES ('InnoDB',0,'io_block_read_cost',3.0,CURRENT_TIMESTAMP,'Using a slower disk for InnoDB');
FLUSH OPTIMIZER_COSTS;

参考

《MySQL 性能优化金字塔法则》

https://dev.mysql.com/doc/refman/5.7/en/system-database.html

https://dev.mysql.com/doc/refman/5.7/en/innodb-persistent-stats.html

https://dev.mysql.com/doc/refman/5.7/en/cost-model.html

http://blog.itpub.net/28218939/viewspace-2653357/

http://blog.itpub.net/28218939/viewspace-2660122/

http://blog.itpub.net/28218939/viewspace-2655228/

发布了297 篇原创文章 · 获赞 35 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/Hehuyi_In/article/details/105329082