MySQL InnoDB INFORMATION_SCHEMA度量表

InnoDB INFORMATION_SCHEMA度量表
MySQL 5.6.2中引入了INNODB_METRICS表,它将所有InnoDB性能和资源相关的计数器合并到一个INFORMATION_SCHEMA表中。

mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME="dml_inserts" \G
*************************** 1. row ***************************
           NAME: dml_inserts
      SUBSYSTEM: dml
          COUNT: 17263004
      MAX_COUNT: 17263004
      MIN_COUNT: NULL
      AVG_COUNT: 0.8178722213173183
    COUNT_RESET: 17263004
MAX_COUNT_RESET: 17263004
MIN_COUNT_RESET: NULL
AVG_COUNT_RESET: NULL
   TIME_ENABLED: 2023-05-10 09:02:54
  TIME_DISABLED: NULL
   TIME_ELAPSED: 21107214
     TIME_RESET: NULL
         STATUS: enabled
           TYPE: status_counter
        COMMENT: Number of rows inserted

启用、禁用和重置计数器
可以使用以下配置选项启用、禁用和重置计数器:
.innodb_monitor_enable:启用一个或多个计数器。

SET GLOBAL innodb_monitor_enable = [counter-name|module_name|pattern|all];

.innodb_monitor_disable:禁用一个或多个计数器。

SET GLOBAL innodb_monitor_disable = [counter-name|module_name|pattern|all];

.innodb_monitor_reset:将一个或多个计数器的计数值重置为零。

SET GLOBAL innodb_monitor_reset = [counter-name|module_name|pattern|all];

.innodb_monitor_reset_all:重置一个或多个计数器的所有值。在使用innodb_monitor_reset_all之前,必须禁用计数器。

SET GLOBAL innodb_monitor_reset_all = [counter-name|module_name|pattern|all];

你也可以在启动时使用MySQL服务器配置文件启用计数器和计数器模块。例如,要启用log模块、metadata_table_handles_opened和metadata_table_handles_closed计数器,在my.cnf配置文件的[mysqld]部分输入以下代码。

[mysqld]
innodb_monitor_enable = module_recovery,metadata_table_handles_opened,metadata_table_handles_closed

当在你的配置文件中启用多个计数器或模块时,你必须指定innodb_monitor_enable配置选项,后面跟着用逗号分隔的计数器和模块名称,如上例所示。只有innodb_monitor_enable选项可以在你的配置文件中使用。禁用和重置配置选项仅支持在命令行上。

注意:
因为每个计数器都会在服务器上增加一定程度的运行时开销,所以通常在试验和基准测试期间在测试和开发服务器上启用更多的计数器,并且仅在生产服务器上启用计数器以诊断已知问题或监视可能成为特定服务器和工作负载瓶颈的方面。

计数器
INNODB_METRICS表中的计数器可能会发生变化,所以要获取最新的计数器列表,可以在运行中的MySQL服务器上查询。

默认启用的计数器与“SHOW ENGINE INNODB STATUS”使用的计数器对应。SHOW ENGINE INNODB STATUS使用的计数器在系统级别上总是“on”的,但是你可以根据需要禁用INNODB_METRICS表的这些计数器。另外,计数器状态不是持久的。除非另外指定,否则计数器在服务器重启时将恢复到默认的启用或禁用状态。

如果你运行的程序会受到INNODB_METRICS表中新增或更改的影响,建议你查看发布说明,并在升级之前查询INNODB_METRICS表中的新版本。

mysql> SELECT name, subsystem, status FROM INFORMATION_SCHEMA.INNODB_METRICS ORDER BY NAME;
+------------------------------------------+---------------------+----------+
| name                                     | subsystem           | status   |
+------------------------------------------+---------------------+----------+
| adaptive_hash_pages_added                | adaptive_hash_index | disabled |
| adaptive_hash_pages_removed              | adaptive_hash_index | disabled |
| adaptive_hash_rows_added                 | adaptive_hash_index | disabled |
| adaptive_hash_rows_deleted_no_hash_entry | adaptive_hash_index | disabled |
| adaptive_hash_rows_removed               | adaptive_hash_index | disabled |
| adaptive_hash_rows_updated               | adaptive_hash_index | disabled |
| adaptive_hash_searches                   | adaptive_hash_index | enabled  |
| adaptive_hash_searches_btree             | adaptive_hash_index | enabled  |
| buffer_data_reads                        | buffer              | enabled  |
| buffer_data_written                      | buffer              | enabled  |
| buffer_flush_adaptive                    | buffer              | disabled |
| buffer_flush_adaptive_avg_pass           | buffer              | disabled |
| buffer_flush_adaptive_avg_time_est       | buffer              | disabled |
| buffer_flush_adaptive_avg_time_slot      | buffer              | disabled |
| buffer_flush_adaptive_avg_time_thread    | buffer              | disabled |
| buffer_flush_adaptive_pages              | buffer              | disabled |
| buffer_flush_adaptive_total_pages        | buffer              | disabled |
| buffer_flush_avg_page_rate               | buffer              | disabled |
| buffer_flush_avg_pass                    | buffer              | disabled |
| buffer_flush_avg_time                    | buffer              | disabled |
| buffer_flush_background                  | buffer              | disabled |
| buffer_flush_background_pages            | buffer              | disabled |
| buffer_flush_background_total_pages      | buffer              | disabled |
| buffer_flush_batches                     | buffer              | disabled |
| buffer_flush_batch_num_scan              | buffer              | disabled |
| buffer_flush_batch_pages                 | buffer              | disabled |
| buffer_flush_batch_scanned               | buffer              | disabled |
| buffer_flush_batch_scanned_per_call      | buffer              | disabled |
| buffer_flush_batch_total_pages           | buffer              | disabled |
| buffer_flush_lsn_avg_rate                | buffer              | disabled |
| buffer_flush_nei***or                    | buffer              | disabled |
| buffer_flush_nei***or_pages              | buffer              | disabled |
| buffer_flush_nei***or_total_pages        | buffer              | disabled |
| buffer_flush_n_to_flush_by_age           | buffer              | disabled |
| buffer_flush_n_to_flush_requested        | buffer              | disabled |
| buffer_flush_pct_for_dirty               | buffer              | disabled |
| buffer_flush_pct_for_lsn                 | buffer              | disabled |
| buffer_flush_sync                        | buffer              | disabled |
| buffer_flush_sync_pages                  | buffer              | disabled |
| buffer_flush_sync_total_pages            | buffer              | disabled |
| buffer_flush_sync_waits                  | buffer              | disabled |
| buffer_LRU_batches_evict                 | buffer              | disabled |
| buffer_LRU_batches_flush                 | buffer              | disabled |
| buffer_LRU_batch_evict_pages             | buffer              | disabled |
| buffer_LRU_batch_evict_total_pages       | buffer              | disabled |
| buffer_LRU_batch_flush_avg_pass          | buffer              | disabled |
| buffer_LRU_batch_flush_avg_time_est      | buffer              | disabled |
| buffer_LRU_batch_flush_avg_time_slot     | buffer              | disabled |
| buffer_LRU_batch_flush_avg_time_thread   | buffer              | disabled |
| buffer_LRU_batch_flush_pages             | buffer              | disabled |
| buffer_LRU_batch_flush_total_pages       | buffer              | disabled |
| buffer_LRU_batch_num_scan                | buffer              | disabled |
| buffer_LRU_batch_scanned                 | buffer              | disabled |
| buffer_LRU_batch_scanned_per_call        | buffer              | disabled |
| buffer_LRU_get_free_loops                | buffer              | disabled |
| buffer_LRU_get_free_search               | Buffer              | disabled |
| buffer_LRU_get_free_waits                | buffer              | disabled |
| buffer_LRU_search_num_scan               | buffer              | disabled |
| buffer_LRU_search_scanned                | buffer              | disabled |
| buffer_LRU_search_scanned_per_call       | buffer              | disabled |
| buffer_LRU_single_flush_failure_count    | Buffer              | disabled |
| buffer_LRU_single_flush_num_scan         | buffer              | disabled |
| buffer_LRU_single_flush_scanned          | buffer              | disabled |
| buffer_LRU_single_flush_scanned_per_call | buffer              | disabled |
| buffer_LRU_unzip_search_num_scan         | buffer              | disabled |
| buffer_LRU_unzip_search_scanned          | buffer              | disabled |
| buffer_LRU_unzip_search_scanned_per_call | buffer              | disabled |
| buffer_pages_created                     | buffer              | enabled  |
| buffer_pages_read                        | buffer              | enabled  |
| buffer_pages_written                     | buffer              | enabled  |
| buffer_page_read_blob                    | buffer_page_io      | disabled |
| buffer_page_read_fsp_hdr                 | buffer_page_io      | disabled |
| buffer_page_read_ibuf_bitmap             | buffer_page_io      | disabled |
| buffer_page_read_ibuf_free_list          | buffer_page_io      | disabled |
| buffer_page_read_index_ibuf_leaf         | buffer_page_io      | disabled |
| buffer_page_read_index_ibuf_non_leaf     | buffer_page_io      | disabled |
| buffer_page_read_index_inode             | buffer_page_io      | disabled |
| buffer_page_read_index_leaf              | buffer_page_io      | disabled |
| buffer_page_read_index_non_leaf          | buffer_page_io      | disabled |
| buffer_page_read_other                   | buffer_page_io      | disabled |
| buffer_page_read_system_page             | buffer_page_io      | disabled |
| buffer_page_read_trx_system              | buffer_page_io      | disabled |
| buffer_page_read_undo_log                | buffer_page_io      | disabled |
| buffer_page_read_xdes                    | buffer_page_io      | disabled |
| buffer_page_read_zblob                   | buffer_page_io      | disabled |
| buffer_page_read_zblob2                  | buffer_page_io      | disabled |
| buffer_page_written_blob                 | buffer_page_io      | disabled |
| buffer_page_written_fsp_hdr              | buffer_page_io      | disabled |
| buffer_page_written_ibuf_bitmap          | buffer_page_io      | disabled |
| buffer_page_written_ibuf_free_list       | buffer_page_io      | disabled |
| buffer_page_written_index_ibuf_leaf      | buffer_page_io      | disabled |
| buffer_page_written_index_ibuf_non_leaf  | buffer_page_io      | disabled |
| buffer_page_written_index_inode          | buffer_page_io      | disabled |
| buffer_page_written_index_leaf           | buffer_page_io      | disabled |
| buffer_page_written_index_non_leaf       | buffer_page_io      | disabled |
| buffer_page_written_other                | buffer_page_io      | disabled |
| buffer_page_written_system_page          | buffer_page_io      | disabled |
| buffer_page_written_trx_system           | buffer_page_io      | disabled |
| buffer_page_written_undo_log             | buffer_page_io      | disabled |
| buffer_page_written_xdes                 | buffer_page_io      | disabled |
| buffer_page_written_zblob                | buffer_page_io      | disabled |
| buffer_page_written_zblob2               | buffer_page_io      | disabled |
| buffer_pool_bytes_data                   | buffer              | enabled  |
| buffer_pool_bytes_dirty                  | buffer              | enabled  |
| buffer_pool_pages_data                   | buffer              | enabled  |
| buffer_pool_pages_dirty                  | buffer              | enabled  |
| buffer_pool_pages_free                   | buffer              | enabled  |
| buffer_pool_pages_misc                   | buffer              | enabled  |
| buffer_pool_pages_total                  | buffer              | enabled  |
| buffer_pool_reads                        | buffer              | enabled  |
| buffer_pool_read_ahead                   | buffer              | enabled  |
| buffer_pool_read_ahead_evicted           | buffer              | enabled  |
| buffer_pool_read_requests                | buffer              | enabled  |
| buffer_pool_size                         | server              | enabled  |
| buffer_pool_wait_free                    | buffer              | enabled  |
| buffer_pool_write_requests               | buffer              | enabled  |
| compression_pad_decrements               | compression         | disabled |
| compression_pad_increments               | compression         | disabled |
| compress_pages_compressed                | compression         | disabled |
| compress_pages_decompressed              | compression         | disabled |
| ddl_background_drop_indexes              | ddl                 | disabled |
| ddl_background_drop_tables               | ddl                 | disabled |
| ddl_log_file_alter_table                 | ddl                 | disabled |
| ddl_online_create_index                  | ddl                 | disabled |
| ddl_pending_alter_table                  | ddl                 | disabled |
| ddl_sort_file_alter_table                | ddl                 | disabled |
| dml_deletes                              | dml                 | enabled  |
| dml_inserts                              | dml                 | enabled  |
| dml_reads                                | dml                 | disabled |
| dml_updates                              | dml                 | enabled  |
| file_num_open_files                      | file_system         | enabled  |
| ibuf_merges                              | change_buffer       | enabled  |
| ibuf_merges_delete                       | change_buffer       | enabled  |
| ibuf_merges_delete_mark                  | change_buffer       | enabled  |
| ibuf_merges_discard_delete               | change_buffer       | enabled  |
| ibuf_merges_discard_delete_mark          | change_buffer       | enabled  |
| ibuf_merges_discard_insert               | change_buffer       | enabled  |
| ibuf_merges_insert                       | change_buffer       | enabled  |
| ibuf_size                                | change_buffer       | enabled  |
| icp_attempts                             | icp                 | disabled |
| icp_match                                | icp                 | disabled |
| icp_no_match                             | icp                 | disabled |
| icp_out_of_range                         | icp                 | disabled |
| index_page_discards                      | index               | disabled |
| index_page_merge_attempts                | index               | disabled |
| index_page_merge_successful              | index               | disabled |
| index_page_reorg_attempts                | index               | disabled |
| index_page_reorg_successful              | index               | disabled |
| index_page_splits                        | index               | disabled |
| innodb_activity_count                    | server              | enabled  |
| innodb_background_drop_table_usec        | server              | disabled |
| innodb_checkpoint_usec                   | server              | disabled |
| innodb_dblwr_pages_written               | server              | enabled  |
| innodb_dblwr_writes                      | server              | enabled  |
| innodb_dict_lru_count                    | server              | disabled |
| innodb_dict_lru_usec                     | server              | disabled |
| innodb_ibuf_merge_usec                   | server              | disabled |
| innodb_log_flush_usec                    | server              | disabled |
| innodb_master_active_loops               | server              | disabled |
| innodb_master_idle_loops                 | server              | disabled |
| innodb_master_purge_usec                 | server              | disabled |
| innodb_master_thread_sleeps              | server              | disabled |
| innodb_mem_validate_usec                 | server              | disabled |
| innodb_page_size                         | server              | enabled  |
| innodb_rwlock_sx_os_waits                | server              | enabled  |
| innodb_rwlock_sx_spin_rounds             | server              | enabled  |
| innodb_rwlock_sx_spin_waits              | server              | enabled  |
| innodb_rwlock_s_os_waits                 | server              | enabled  |
| innodb_rwlock_s_spin_rounds              | server              | enabled  |
| innodb_rwlock_s_spin_waits               | server              | enabled  |
| innodb_rwlock_x_os_waits                 | server              | enabled  |
| innodb_rwlock_x_spin_rounds              | server              | enabled  |
| innodb_rwlock_x_spin_waits               | server              | enabled  |
| lock_deadlocks                           | lock                | enabled  |
| lock_rec_locks                           | lock                | disabled |
| lock_rec_lock_created                    | lock                | disabled |
| lock_rec_lock_removed                    | lock                | disabled |
| lock_rec_lock_requests                   | lock                | disabled |
| lock_rec_lock_waits                      | lock                | disabled |
| lock_row_lock_current_waits              | lock                | enabled  |
| lock_row_lock_time                       | lock                | enabled  |
| lock_row_lock_time_avg                   | lock                | enabled  |
| lock_row_lock_time_max                   | lock                | enabled  |
| lock_row_lock_waits                      | lock                | enabled  |
| lock_table_locks                         | lock                | disabled |
| lock_table_lock_created                  | lock                | disabled |
| lock_table_lock_removed                  | lock                | disabled |
| lock_table_lock_waits                    | lock                | disabled |
| lock_timeouts                            | lock                | enabled  |
| log_checkpoints                          | recovery            | disabled |
| log_lsn_buf_pool_oldest                  | recovery            | disabled |
| log_lsn_checkpoint_age                   | recovery            | disabled |
| log_lsn_current                          | recovery            | disabled |
| log_lsn_last_checkpoint                  | recovery            | disabled |
| log_lsn_last_flush                       | recovery            | disabled |
| log_max_modified_age_async               | recovery            | disabled |
| log_max_modified_age_sync                | recovery            | disabled |
| log_num_log_io                           | recovery            | disabled |
| log_padded                               | recovery            | enabled  |
| log_pending_checkpoint_writes            | recovery            | disabled |
| log_pending_log_flushes                  | recovery            | disabled |
| log_waits                                | recovery            | enabled  |
| log_writes                               | recovery            | enabled  |
| log_write_requests                       | recovery            | enabled  |
| metadata_table_handles_closed            | metadata            | disabled |
| metadata_table_handles_opened            | metadata            | disabled |
| metadata_table_reference_count           | metadata            | disabled |
| os_data_fsyncs                           | os                  | enabled  |
| os_data_reads                            | os                  | enabled  |
| os_data_writes                           | os                  | enabled  |
| os_log_bytes_written                     | os                  | enabled  |
| os_log_fsyncs                            | os                  | enabled  |
| os_log_pending_fsyncs                    | os                  | enabled  |
| os_log_pending_writes                    | os                  | enabled  |
| os_pending_reads                         | os                  | disabled |
| os_pending_writes                        | os                  | disabled |
| purge_del_mark_records                   | purge               | disabled |
| purge_dml_delay_usec                     | purge               | disabled |
| purge_invoked                            | purge               | disabled |
| purge_resume_count                       | purge               | disabled |
| purge_stop_count                         | purge               | disabled |
| purge_undo_log_pages                     | purge               | disabled |
| purge_upd_exist_or_extern_records        | purge               | disabled |
| trx_active_transactions                  | transaction         | disabled |
| trx_commits_insert_update                | transaction         | disabled |
| trx_nl_ro_commits                        | transaction         | disabled |
| trx_rollbacks                            | transaction         | disabled |
| trx_rollbacks_savepoint                  | transaction         | disabled |
| trx_rollback_active                      | transaction         | disabled |
| trx_ro_commits                           | transaction         | disabled |
| trx_rseg_current_size                    | transaction         | disabled |
| trx_rseg_history_len                     | transaction         | enabled  |
| trx_rw_commits                           | transaction         | disabled |
| trx_undo_slots_cached                    | transaction         | disabled |
| trx_undo_slots_used                      | transaction         | disabled |
+------------------------------------------+---------------------+----------+
235 rows in set (0.03 sec)

计数器模块
模块名与INNODB_METRICS表中的SUBSYSTEM列对应,但不完全相同。相对于单独启用、禁用或重置计数器,您可以使用模块名称来快速启用、禁用或重置特定子系统的所有计数器。例如,使用module_dml启用与dml子系统关联的所有计数器。

mysql> SELECT name, subsystem, status FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE subsystem ='dml';
+-------------+-----------+----------+
| name        | subsystem | status   |
+-------------+-----------+----------+
| dml_reads   | dml       | disabled |
| dml_inserts | dml       | enabled  |
| dml_deletes | dml       | enabled  |
| dml_updates | dml       | enabled  |
+-------------+-----------+----------+
4 rows in set (0.00 sec)

mysql> SET GLOBAL innodb_monitor_enable = module_dml;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT name, subsystem, status FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE subsystem ='dml';
+-------------+-----------+---------+
| name        | subsystem | status  |
+-------------+-----------+---------+
| dml_reads   | dml       | enabled |
| dml_inserts | dml       | enabled |
| dml_deletes | dml       | enabled |
| dml_updates | dml       | enabled |
+-------------+-----------+---------+
4 rows in set (0.00 sec)

下面是innodb_monitor_enable和相关的配置选项可以使用的module_name值以及相应的子系统名称。

.module_adaptive_hash (subsystem = adaptive_hash_index)
.module_buffer (subsystem = buffer)
.module_buffer_page (subsystem = buffer_page_io)
.module_compress (subsystem = compression)
.module_ddl (subsystem = ddl)
.module_dml (subsystem = dml)
.module_file (subsystem = file_system)
.module_ibuf_system (subsystem = change_buffer)
.module_icp (subsystem = icp)
.module_index (subsystem = index)
.module_innodb (subsystem = innodb)
.module_lock (subsystem = lock)
.module_log (subsystem = recovery)
.module_metadata (subsystem = metadata)
.module_os (subsystem = os)
.module_purge (subsystem = purge)
.module_trx (subsystem = transaction)

使用INNODB_METRICS表计数器
下面这个例子演示了启用、禁用、重置计数器,以及查询INNODB_METRICS表中的计数器数据。

1.创建一个简单的InnoDB表;

mysql> use test
Database changed
mysql> CREATE TABLE t1 (c1 INT) ENGINE=INNODB;
Query OK, 0 rows affected (0.01 sec)

2.启用dml_inserts计数器。
先禁用dml_inserts计数器并将所有计数清零

mysql> SET GLOBAL innodb_monitor_disable=dml_inserts;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME="dml_inserts" \G
*************************** 1. row ***************************
           NAME: dml_inserts
      SUBSYSTEM: dml
          COUNT: 17263007
      MAX_COUNT: 17263007
      MIN_COUNT: NULL
      AVG_COUNT: 0.817808627174022
    COUNT_RESET: 0
MAX_COUNT_RESET: 0
MIN_COUNT_RESET: NULL
AVG_COUNT_RESET: 0
   TIME_ENABLED: 2023-05-10 09:02:54
  TIME_DISABLED: 2024-01-09 16:37:13
   TIME_ELAPSED: 21108859
     TIME_RESET: NULL
         STATUS: disabled
           TYPE: status_counter
        COMMENT: Number of rows inserted
1 row in set (0.00 sec)

mysql> SET GLOBAL innodb_monitor_reset_all=dml_inserts;
Query OK, 0 rows affected (0.05 sec)

mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME="dml_inserts" \G
*************************** 1. row ***************************
           NAME: dml_inserts
      SUBSYSTEM: dml
          COUNT: 0
      MAX_COUNT: NULL
      MIN_COUNT: NULL
      AVG_COUNT: NULL
    COUNT_RESET: 0
MAX_COUNT_RESET: NULL
MIN_COUNT_RESET: NULL
AVG_COUNT_RESET: NULL
   TIME_ENABLED: NULL
  TIME_DISABLED: NULL
   TIME_ELAPSED: NULL
     TIME_RESET: NULL
         STATUS: disabled
           TYPE: status_counter
        COMMENT: Number of rows inserted
1 row in set (0.00 sec)

再启用dml_inserts计数器

mysql> SET GLOBAL innodb_monitor_enable = dml_inserts;
Query OK, 0 rows affected (0.00 sec)

在INNODB_METRICS表的COMMENT列中找到的关于dml_inserts计数器的描述:

mysql> SELECT NAME, COMMENT FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME="dml_inserts";
+-------------+-------------------------+
| NAME        | COMMENT                 |
+-------------+-------------------------+
| dml_inserts | Number of rows inserted |
+-------------+-------------------------+
1 row in set (0.00 sec)

3.查询INNODB_METRICS表中的dml_inserts计数器数据。因为没有执行DML操作,所以计数器值为零或NULL。TIME_ENABLED和TIME_ELAPSED值表示计数器上次启用的时间,以及从该时间起已经过去了多少秒。

mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME="dml_inserts" \G
*************************** 1. row ***************************
           NAME: dml_inserts
      SUBSYSTEM: dml
          COUNT: 0
      MAX_COUNT: 0
      MIN_COUNT: NULL
      AVG_COUNT: 0
    COUNT_RESET: 0
MAX_COUNT_RESET: 0
MIN_COUNT_RESET: NULL
AVG_COUNT_RESET: NULL
   TIME_ENABLED: 2024-01-09 16:40:33
  TIME_DISABLED: NULL
   TIME_ELAPSED: 150
     TIME_RESET: NULL
         STATUS: enabled
           TYPE: status_counter
        COMMENT: Number of rows inserted
1 row in set (0.00 sec)

4.向表中插入三行数据。

mysql> INSERT INTO t1 values(1);
Query OK, 1 row affected (0.01 sec)

mysql> INSERT INTO t1 values(2);
Query OK, 1 row affected (0.01 sec)

mysql> INSERT INTO t1 values(3);
Query OK, 1 row affected (0.00 sec)

5.再次查询INNODB_METRICS表获取dml_inserts计数器数据。现在有一些计数器的值已经递增,包括COUNT、MAX_COUNT、AVG_COUNT和COUNT_RESET。

mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME="dml_inserts"\G
*************************** 1. row ***************************
           NAME: dml_inserts
      SUBSYSTEM: dml
          COUNT: 3
      MAX_COUNT: 3
      MIN_COUNT: NULL
      AVG_COUNT: 0.00980392156862745
    COUNT_RESET: 3
MAX_COUNT_RESET: 3
MIN_COUNT_RESET: NULL
AVG_COUNT_RESET: NULL
   TIME_ENABLED: 2024-01-09 16:40:33
  TIME_DISABLED: NULL
   TIME_ELAPSED: 306
     TIME_RESET: NULL
         STATUS: enabled
           TYPE: status_counter
        COMMENT: Number of rows inserted
1 row in set (0.00 sec)

6.重置dml_inserts计数器,然后再次在INNODB_METRICS表中查询dml_inserts计数器数据。之前报告的%_RESET值,如COUNT_RESET和MAX_RESET,将重置为零。COUNT、MAX_COUNT和AVG_COUNT等值从计数器启用时开始收集数据,这些值不受重置的影响。

mysql> SET GLOBAL innodb_monitor_disable=dml_inserts;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME="dml_inserts"\G
*************************** 1. row ***************************
           NAME: dml_inserts
      SUBSYSTEM: dml
          COUNT: 20
      MAX_COUNT: 20
      MIN_COUNT: NULL
      AVG_COUNT: 0.03424657534246575
    COUNT_RESET: 0
MAX_COUNT_RESET: 0
MIN_COUNT_RESET: NULL
AVG_COUNT_RESET: 0
   TIME_ENABLED: 2024-01-09 16:40:33
  TIME_DISABLED: 2024-01-09 16:50:17
   TIME_ELAPSED: 584
     TIME_RESET: NULL
         STATUS: disabled
           TYPE: status_counter
        COMMENT: Number of rows inserted
1 row in set (0.00 sec)

7.要重置所有计数器值,必须首先禁用计数器。禁用计数器将状态值设置为禁用。

mysql> SET GLOBAL innodb_monitor_disable=dml_inserts;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME="dml_inserts"\G
*************************** 1. row ***************************
           NAME: dml_inserts
      SUBSYSTEM: dml
          COUNT: 20
      MAX_COUNT: 20
      MIN_COUNT: NULL
      AVG_COUNT: 0.03076923076923077
    COUNT_RESET: 0
MAX_COUNT_RESET: 0
MIN_COUNT_RESET: NULL
AVG_COUNT_RESET: 0
   TIME_ENABLED: 2024-01-09 16:40:33
  TIME_DISABLED: 2024-01-09 16:51:23
   TIME_ELAPSED: 650
     TIME_RESET: NULL
         STATUS: disabled
           TYPE: status_counter
        COMMENT: Number of rows inserted
1 row in set (0.01 sec)

注意:
计数器和模块名称支持通配符匹配。例如,可以指定dml_i%,而不是指定完整的dml_inserts计数器名称。还可以使用通配符匹配一次启用、禁用或重置多个计数器或模块。例如,指定dml_%来启用、禁用或重置所有以dml_%开头的计数器。

8.当计数器被禁用后,你可以使用innodb_monitor_reset_all选项重置所有计数器的值。所有值都设置为0或NULL。

mysql> SET GLOBAL innodb_monitor_reset_all=dml_inserts;
Query OK, 0 rows affected (0.05 sec)

mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME="dml_inserts"\G
*************************** 1. row ***************************
           NAME: dml_inserts
      SUBSYSTEM: dml
          COUNT: 0
      MAX_COUNT: NULL
      MIN_COUNT: NULL
      AVG_COUNT: NULL
    COUNT_RESET: 0
MAX_COUNT_RESET: NULL
MIN_COUNT_RESET: NULL
AVG_COUNT_RESET: NULL
   TIME_ENABLED: NULL
  TIME_DISABLED: NULL
   TIME_ELAPSED: NULL
     TIME_RESET: NULL
         STATUS: disabled
           TYPE: status_counter
        COMMENT: Number of rows inserted
1 row in set (0.00 sec)

MySQL InnoDB INFORMATION_SCHEMA缓冲池表

InnoDB INFORMATION_SCHEMA缓冲池表
InnoDB INFORMATION_SCHEMA缓冲池表提供了缓冲池状态信息和InnoDB缓冲池中页的元数据。这些表是在MySQL 5.6.2中引入的,后来移植到MySQL 5.5 (MySQL 5.5.28)和MySQL 5.1 (MySQL 5.1.66)。

InnoDB INFORMATION_SCHEMA缓冲池表包括下面这些表:

mysql> show tables from information_schema like 'INNODB_BUFFER%';
+-----------------------------------------------+
| Tables_in_information_schema (INNODB_BUFFER%) |
+-----------------------------------------------+
| INNODB_BUFFER_PAGE_LRU                        |
| INNODB_BUFFER_PAGE                            |
| INNODB_BUFFER_POOL_STATS                      |
+-----------------------------------------------+
3 rows in set (0.00 sec)

.INNODB_BUFFER_PAGE:保存InnoDB缓冲池中每一页的信息。

.INNODB_BUFFER_PAGE_LRU:保存了关于InnoDB缓冲池中页的信息,特别是它们在LRU列表中的排序方式,该列表决定了当缓冲池满时从缓冲池中清除哪些页。INNODB_BUFFER_PAGE_LRU表和INNODB_BUFFER_PAGE表有相同的列,不同的是INNODB_BUFFER_PAGE_LRU表有一个LRU_POSITION列而不是BLOCK_ID列。

.INNODB_BUFFER_POOL_STATS:缓冲池状态信息。大部分相同的信息由SHOW ENGINE INNODB STATUS输出提供,或者可以通过使用INNODB缓冲池服务器状态变量获得。

警示:
查询INNODB_BUFFER_PAGE表或INNODB_BUFFER_PAGE_LRU表会引入显著的性能开销。不要在生产系统上查询这些表,除非您意识到您的查询可能产生的性能影响,并确定它是可接受的。为了避免影响性能,在测试实例上重现您想要调查的问题,并在测试实例上运行您的查询。

查询INNODB_BUFFER_PAGE表中的系统数据
该查询通过排除TABLE_NAME值为NULL或包含表名中有斜杠/或句点.的表名表示用户自定义表,提供了包含系统数据的页面的大致数量。

mysql> select count(*) from information_schema.innodb_buffer_page
    -> where table_name is null or (instr(table_name, '/') = 0 and instr(table_name, '.') = 0);
+----------+
| count(*) |
+----------+
|   451428 |
+----------+
1 row in set (1.80 sec)

该查询返回包含系统数据的大约页数、缓冲池页数和包含系统数据的大约百分比的页数。

mysql> select
    -> (select count(*) from information_schema.innodb_buffer_page
    -> where table_name is null or (instr(table_name, '/') = 0 and instr(table_name, '.') = 0)
    -> ) as system_pages,
    -> (
    -> select count(*)
    -> from information_schema.innodb_buffer_page
    -> ) as total_pages,
    -> (
    -> select round((system_pages/total_pages) * 100)
    -> ) as system_page_percentage;
+--------------+-------------+------------------------+
| system_pages | total_pages | system_page_percentage |
+--------------+-------------+------------------------+
|       451428 |      524224 |                     86 |
+--------------+-------------+------------------------+
1 row in set (3.35 sec)

通过查询PAGE_TYPE的值,可以确定缓冲池中系统数据的类型。例如,下面的查询返回包含系统数据的页的10个不同的PAGE_TYPE值:

mysql> select distinct page_type from information_schema.innodb_buffer_page
    -> where table_name is null or (instr(table_name, '/') = 0 and instr(table_name, '.') = 0);
+-------------------+
| page_type         |
+-------------------+
| SYSTEM            |
| INODE             |
| IBUF_INDEX        |
| INDEX             |
| IBUF_BITMAP       |
| TRX_SYSTEM        |
| FILE_SPACE_HEADER |
| UNKNOWN           |
| UNDO_LOG          |
| EXTENT_DESCRIPTOR |
+-------------------+
10 rows in set (2.02 sec)

查询INNODB_BUFFER_PAGE表中的用户数据
这个查询通过统计TABLE_NAME值不为NULL且不像’%INNODB_SYS_TABLES%’的页面,提供了包含用户数据的页面的近似计数。

mysql> select count(*) from information_schema.innodb_buffer_page
    -> where table_name is not null and table_name not like '%innodb_sys_tables%';
+----------+
| count(*) |
+----------+
|    91067 |
+----------+
1 row in set (1.67 sec)

该查询返回包含用户数据的页面的大致数量、缓冲池页面的总数以及包含用户数据的页面的大致百分比。

mysql> select
    -> (select count(*) from information_schema.innodb_buffer_page
    -> where table_name is not null and (instr(table_name, '/') > 0 or instr(table_name, '.') > 0)
    -> ) as user_pages,
    -> (
    -> select count(*)
    -> from information_schema.innodb_buffer_page
    -> ) as total_pages,
    -> (
    -> select round((user_pages/total_pages) * 100)
    -> ) as user_page_percentage;
+------------+-------------+----------------------+
| user_pages | total_pages | user_page_percentage |
+------------+-------------+----------------------+
|      72796 |      524224 |                   14 |
+------------+-------------+----------------------+
1 row in set (3.31 sec)

这个查询将使用缓冲池中的页的用户定义的表标识出来:

mysql> select distinct table_name from information_schema.innodb_buffer_page
    -> where table_name is not null and (instr(table_name, '/') > 0 or instr(table_name, '.') > 0)
    -> and table_name not like '`mysql`.`innodb_%';
+--------------------------------------------------------+
| table_name                                             |
+--------------------------------------------------------+
| `undo`.`opening_lines`                                 |
| `undo`.`FTS_00000000000001d9_00000000000002da_INDEX_3` |
| `mysql`.`help_category`                                |
| `mysql`.`help_topic`                                   |
| `undo`.`big_table`                                     |
| `undo`.`key_block_size_4`                              |
| `sys`.`sys_config`                                     |
| `test`.`FTS_000000000000020c_DELETED_CACHE`            |
| `undo`.`FTS_00000000000001d9_BEING_DELETED`            |
| `undo`.`FTS_00000000000001d9_00000000000002da_INDEX_4` |
| `mysql`.`help_relation`                                |
| `undo`.`t8`                                            |
| `test`.`FTS_000000000000020c_0000000000000310_INDEX_1` |
| `mysql`.`slave_relay_log_info`                         |
| `undo`.`FTS_00000000000001d9_BEING_DELETED_CACHE`      |
| `undo`.`FTS_00000000000001d9_00000000000002da_INDEX_5` |
| `mysql`.`help_keyword`                                 |
| `undo`.`employees`                                     |
| `undo`.`t13`                                           |
| `test`.`FTS_000000000000020c_0000000000000310_INDEX_2` |
| `mysql`.`time_zone_name`                               |
| `mysql`.`slave_master_info`                            |
| `test`.`t7`                                            |
| `test`.`user`                                          |
| `undo`.`FTS_00000000000001d9_CONFIG`                   |
| `undo`.`FTS_00000000000001d9_00000000000002da_INDEX_6` |
| `undo`.`t9`                                            |
| `undo`.`t14`                                           |
| `test`.`articles`                                      |
| `test`.`FTS_000000000000020c_0000000000000310_INDEX_3` |
| `mysql`.`time_zone`                                    |
| `mysql`.`slave_worker_info`                            |
| `test`.`t8`                                            |
| `undo`.`FTS_00000000000001d9_DELETED`                  |
| `undo`.`t1`                                            |
| `undo`.`t10`                                           |
| `test`.`t1`                                            |
| `test`.`FTS_000000000000020c_BEING_DELETED`            |
| `test`.`FTS_000000000000020c_0000000000000310_INDEX_4` |
| `mysql`.`plugin`                                       |
| `mysql`.`gtid_executed`                                |
| `mysql`.`time_zone_transition`                         |
| `undo`.`FTS_00000000000001d9_DELETED_CACHE`            |
| `undo`.`t2`                                            |
| `undo`.`t11`                                           |
| `test`.`parent`                                        |
| `test`.`FTS_000000000000020c_BEING_DELETED_CACHE`      |
| `test`.`FTS_000000000000020c_0000000000000310_INDEX_5` |
| `mysql`.`server_cost`                                  |
| `mysql`.`time_zone_transition_type`                    |
| `mysql`.`servers`                                      |
| `undo`.`FTS_00000000000001d9_00000000000002da_INDEX_1` |
| `undo`.`t7`                                            |
| `test`.`child`                                         |
| `test`.`FTS_000000000000020c_CONFIG`                   |
| `test`.`FTS_000000000000020c_0000000000000310_INDEX_6` |
| `mysql`.`engine_cost`                                  |
| `mysql`.`time_zone_leap_second`                        |
| `undo`.`FTS_00000000000001d9_00000000000002da_INDEX_2` |
| `undo`.`t12`                                           |
| `test`.`abc`                                           |
| `test`.`FTS_000000000000020c_DELETED`                  |
+--------------------------------------------------------+
62 rows in set (1.81 sec)

查询INNODB_BUFFER_PAGE表中的索引数据
有关索引页的信息,请使用索引的名称查询INDEX_NAME列。例如,下面的查询返回在employees.salaries表上定义的emp_no索引的页数和总数据大小:

mysql> select index_name, count(*) as pages,
    -> round(sum(if(compressed_size = 0, @@global.innodb_page_size, compressed_size))/1024/1024)
    -> as 'total data (mb)'
    -> from information_schema.innodb_buffer_page
    -> where index_name='emp_no' and table_name = '`employees`.`salaries`';
+------------+-------+-----------------+
| index_name | pages | total data (mb) |
+------------+-------+-----------------+
| emp_no     |    44 |               1 |
+------------+-------+-----------------+
1 row in set (1.75 sec)

该查询返回在employees.salaries表上定义的所有索引的页数和总数据大小:

mysql> select index_name, count(*) as pages,
    -> round(sum(if(compressed_size = 0, @@global.innodb_page_size, compressed_size))/1024/1024)
    -> as 'total data (mb)'
    -> from information_schema.innodb_buffer_page
    -> where table_name = '`employees`.`salaries`'
    -> group by index_name;
+------------+-------+-----------------+
| index_name | pages | total data (mb) |
+------------+-------+-----------------+
| emp_no     |    44 |               1 |
| idx_salary |    65 |               1 |
| PRIMARY    |  6086 |              95 |
+------------+-------+-----------------+
3 rows in set (1.73 sec)

查询INNODB_BUFFER_PAGE_LRU表中的LRU_POSITION数据
INNODB_BUFFER_PAGE_LRU表保存了InnoDB缓冲池中页的信息,特别是当缓冲池满时,它们是如何排序的,这决定了哪些页需要从缓冲池中移除。该表的定义与INNODB_BUFFER_PAGE表相同,不同之处在于该表有一个LRU_POSITION列而不是BLOCK_ID列。

该查询计算LRU链表中特定位置上employees.employees表所使用的页数:

mysql> select count(lru_position) from information_schema.innodb_buffer_page_lru
    -> where table_name='`employees`.`employees`' and lru_position < 6570;
+---------------------+
| count(lru_position) |
+---------------------+
|                  13 |
+---------------------+
1 row in set (0.58 sec)

查询INNODB_BUFFER_POOL_STATS表
INNODB_BUFFER_POOL_STATS表提供了类似于SHOW ENGINE INNODB STATUS和INNODB缓冲池状态变量的信息。

mysql> select * from information_schema.innodb_buffer_pool_stats \G
*************************** 1. row ***************************
                         POOL_ID: 0
                       POOL_SIZE: 65528
                    FREE_BUFFERS: 46471
                  DATABASE_PAGES: 17936
              OLD_DATABASE_PAGES: 6640
         MODIFIED_DATABASE_PAGES: 0
              PENDING_DECOMPRESS: 4480
                   PENDING_READS: 0
               PENDING_FLUSH_LRU: 0
              PENDING_FLUSH_LIST: 0
                PAGES_MADE_YOUNG: 16823
            PAGES_NOT_MADE_YOUNG: 19769
           PAGES_MADE_YOUNG_RATE: 0
       PAGES_MADE_NOT_YOUNG_RATE: 0
               NUMBER_PAGES_READ: 857
            NUMBER_PAGES_CREATED: 17087
            NUMBER_PAGES_WRITTEN: 24505
                 PAGES_READ_RATE: 0
               PAGES_CREATE_RATE: 0
              PAGES_WRITTEN_RATE: 0
                NUMBER_PAGES_GET: 3448729
                        HIT_RATE: 0
    YOUNG_MAKE_PER_THOUSAND_GETS: 0
NOT_YOUNG_MAKE_PER_THOUSAND_GETS: 0
         NUMBER_PAGES_READ_AHEAD: 768
       NUMBER_READ_AHEAD_EVICTED: 0
                 READ_AHEAD_RATE: 0
         READ_AHEAD_EVICTED_RATE: 0
                    LRU_IO_TOTAL: 0
                  LRU_IO_CURRENT: 0
                UNCOMPRESS_TOTAL: 0
              UNCOMPRESS_CURRENT: 0
*************************** 2. row ***************************
                         POOL_ID: 1
                       POOL_SIZE: 65528
                    FREE_BUFFERS: 47000
                  DATABASE_PAGES: 17515
              OLD_DATABASE_PAGES: 6485
         MODIFIED_DATABASE_PAGES: 0
              PENDING_DECOMPRESS: 4051
                   PENDING_READS: 0
               PENDING_FLUSH_LRU: 0
              PENDING_FLUSH_LIST: 0
                PAGES_MADE_YOUNG: 0
            PAGES_NOT_MADE_YOUNG: 0
           PAGES_MADE_YOUNG_RATE: 0
       PAGES_MADE_NOT_YOUNG_RATE: 0
               NUMBER_PAGES_READ: 864
            NUMBER_PAGES_CREATED: 16651
            NUMBER_PAGES_WRITTEN: 23771
                 PAGES_READ_RATE: 0
               PAGES_CREATE_RATE: 0
              PAGES_WRITTEN_RATE: 0
                NUMBER_PAGES_GET: 5410983
                        HIT_RATE: 0
    YOUNG_MAKE_PER_THOUSAND_GETS: 0
NOT_YOUNG_MAKE_PER_THOUSAND_GETS: 0
         NUMBER_PAGES_READ_AHEAD: 832
       NUMBER_READ_AHEAD_EVICTED: 0
                 READ_AHEAD_RATE: 0
         READ_AHEAD_EVICTED_RATE: 0
                    LRU_IO_TOTAL: 0
                  LRU_IO_CURRENT: 0
                UNCOMPRESS_TOTAL: 0
              UNCOMPRESS_CURRENT: 0
*************************** 3. row ***************************
                         POOL_ID: 2
                       POOL_SIZE: 65528
                    FREE_BUFFERS: 46659
                  DATABASE_PAGES: 17733
              OLD_DATABASE_PAGES: 6565
         MODIFIED_DATABASE_PAGES: 0
              PENDING_DECOMPRESS: 4544
                   PENDING_READS: 0
               PENDING_FLUSH_LRU: 0
              PENDING_FLUSH_LIST: 0
                PAGES_MADE_YOUNG: 0
            PAGES_NOT_MADE_YOUNG: 0
           PAGES_MADE_YOUNG_RATE: 0
       PAGES_MADE_NOT_YOUNG_RATE: 0
               NUMBER_PAGES_READ: 755
            NUMBER_PAGES_CREATED: 16978
            NUMBER_PAGES_WRITTEN: 23908
                 PAGES_READ_RATE: 0
               PAGES_CREATE_RATE: 0
              PAGES_WRITTEN_RATE: 0
                NUMBER_PAGES_GET: 3462987
                        HIT_RATE: 0
    YOUNG_MAKE_PER_THOUSAND_GETS: 0
NOT_YOUNG_MAKE_PER_THOUSAND_GETS: 0
         NUMBER_PAGES_READ_AHEAD: 640
       NUMBER_READ_AHEAD_EVICTED: 0
                 READ_AHEAD_RATE: 0
         READ_AHEAD_EVICTED_RATE: 0
                    LRU_IO_TOTAL: 0
                  LRU_IO_CURRENT: 0
                UNCOMPRESS_TOTAL: 0
              UNCOMPRESS_CURRENT: 0
*************************** 4. row ***************************
                         POOL_ID: 3
                       POOL_SIZE: 65528
                    FREE_BUFFERS: 46644
                  DATABASE_PAGES: 17751
              OLD_DATABASE_PAGES: 6572
         MODIFIED_DATABASE_PAGES: 0
              PENDING_DECOMPRESS: 4528
                   PENDING_READS: 0
               PENDING_FLUSH_LRU: 0
              PENDING_FLUSH_LIST: 0
                PAGES_MADE_YOUNG: 2251
            PAGES_NOT_MADE_YOUNG: 17746
           PAGES_MADE_YOUNG_RATE: 0
       PAGES_MADE_NOT_YOUNG_RATE: 0
               NUMBER_PAGES_READ: 802
            NUMBER_PAGES_CREATED: 16961
            NUMBER_PAGES_WRITTEN: 23848
                 PAGES_READ_RATE: 0
               PAGES_CREATE_RATE: 0
              PAGES_WRITTEN_RATE: 0
                NUMBER_PAGES_GET: 4188354
                        HIT_RATE: 0
    YOUNG_MAKE_PER_THOUSAND_GETS: 0
NOT_YOUNG_MAKE_PER_THOUSAND_GETS: 0
         NUMBER_PAGES_READ_AHEAD: 768
       NUMBER_READ_AHEAD_EVICTED: 0
                 READ_AHEAD_RATE: 0
         READ_AHEAD_EVICTED_RATE: 0
                    LRU_IO_TOTAL: 0
                  LRU_IO_CURRENT: 0
                UNCOMPRESS_TOTAL: 0
              UNCOMPRESS_CURRENT: 0
*************************** 5. row ***************************
                         POOL_ID: 4
                       POOL_SIZE: 65528
                    FREE_BUFFERS: 46660
                  DATABASE_PAGES: 17729
              OLD_DATABASE_PAGES: 6564
         MODIFIED_DATABASE_PAGES: 0
              PENDING_DECOMPRESS: 4550
                   PENDING_READS: 0
               PENDING_FLUSH_LRU: 0
              PENDING_FLUSH_LIST: 0
                PAGES_MADE_YOUNG: 0
            PAGES_NOT_MADE_YOUNG: 0
           PAGES_MADE_YOUNG_RATE: 0
       PAGES_MADE_NOT_YOUNG_RATE: 0
               NUMBER_PAGES_READ: 792
            NUMBER_PAGES_CREATED: 16937
            NUMBER_PAGES_WRITTEN: 24222
                 PAGES_READ_RATE: 0
               PAGES_CREATE_RATE: 0
              PAGES_WRITTEN_RATE: 0
                NUMBER_PAGES_GET: 4314265
                        HIT_RATE: 0
    YOUNG_MAKE_PER_THOUSAND_GETS: 0
NOT_YOUNG_MAKE_PER_THOUSAND_GETS: 0
         NUMBER_PAGES_READ_AHEAD: 768
       NUMBER_READ_AHEAD_EVICTED: 0
                 READ_AHEAD_RATE: 0
         READ_AHEAD_EVICTED_RATE: 0
                    LRU_IO_TOTAL: 0
                  LRU_IO_CURRENT: 0
                UNCOMPRESS_TOTAL: 0
              UNCOMPRESS_CURRENT: 0
*************************** 6. row ***************************
                         POOL_ID: 5
                       POOL_SIZE: 65528
                    FREE_BUFFERS: 46748
                  DATABASE_PAGES: 17642
              OLD_DATABASE_PAGES: 6532
         MODIFIED_DATABASE_PAGES: 0
              PENDING_DECOMPRESS: 4548
                   PENDING_READS: 0
               PENDING_FLUSH_LRU: 0
              PENDING_FLUSH_LIST: 0
                PAGES_MADE_YOUNG: 0
            PAGES_NOT_MADE_YOUNG: 0
           PAGES_MADE_YOUNG_RATE: 0
       PAGES_MADE_NOT_YOUNG_RATE: 0
               NUMBER_PAGES_READ: 790
            NUMBER_PAGES_CREATED: 16852
            NUMBER_PAGES_WRITTEN: 23741
                 PAGES_READ_RATE: 0
               PAGES_CREATE_RATE: 0
              PAGES_WRITTEN_RATE: 0
                NUMBER_PAGES_GET: 3449085
                        HIT_RATE: 0
    YOUNG_MAKE_PER_THOUSAND_GETS: 0
NOT_YOUNG_MAKE_PER_THOUSAND_GETS: 0
         NUMBER_PAGES_READ_AHEAD: 768
       NUMBER_READ_AHEAD_EVICTED: 0
                 READ_AHEAD_RATE: 0
         READ_AHEAD_EVICTED_RATE: 0
                    LRU_IO_TOTAL: 0
                  LRU_IO_CURRENT: 0
                UNCOMPRESS_TOTAL: 0
              UNCOMPRESS_CURRENT: 0
*************************** 7. row ***************************
                         POOL_ID: 6
                       POOL_SIZE: 65528
                    FREE_BUFFERS: 46821
                  DATABASE_PAGES: 17571
              OLD_DATABASE_PAGES: 6506
         MODIFIED_DATABASE_PAGES: 0
              PENDING_DECOMPRESS: 4544
                   PENDING_READS: 0
               PENDING_FLUSH_LRU: 0
              PENDING_FLUSH_LIST: 0
                PAGES_MADE_YOUNG: 0
            PAGES_NOT_MADE_YOUNG: 0
           PAGES_MADE_YOUNG_RATE: 0
       PAGES_MADE_NOT_YOUNG_RATE: 0
               NUMBER_PAGES_READ: 727
            NUMBER_PAGES_CREATED: 16844
            NUMBER_PAGES_WRITTEN: 24005
                 PAGES_READ_RATE: 0
               PAGES_CREATE_RATE: 0
              PAGES_WRITTEN_RATE: 0
                NUMBER_PAGES_GET: 3852166
                        HIT_RATE: 0
    YOUNG_MAKE_PER_THOUSAND_GETS: 0
NOT_YOUNG_MAKE_PER_THOUSAND_GETS: 0
         NUMBER_PAGES_READ_AHEAD: 704
       NUMBER_READ_AHEAD_EVICTED: 0
                 READ_AHEAD_RATE: 0
         READ_AHEAD_EVICTED_RATE: 0
                    LRU_IO_TOTAL: 0
                  LRU_IO_CURRENT: 0
                UNCOMPRESS_TOTAL: 0
              UNCOMPRESS_CURRENT: 0
*************************** 8. row ***************************
                         POOL_ID: 7
                       POOL_SIZE: 65528
                    FREE_BUFFERS: 46651
                  DATABASE_PAGES: 17749
              OLD_DATABASE_PAGES: 6571
         MODIFIED_DATABASE_PAGES: 0
              PENDING_DECOMPRESS: 4512
                   PENDING_READS: 0
               PENDING_FLUSH_LRU: 0
              PENDING_FLUSH_LIST: 0
                PAGES_MADE_YOUNG: 0
            PAGES_NOT_MADE_YOUNG: 0
           PAGES_MADE_YOUNG_RATE: 0
       PAGES_MADE_NOT_YOUNG_RATE: 0
               NUMBER_PAGES_READ: 804
            NUMBER_PAGES_CREATED: 16945
            NUMBER_PAGES_WRITTEN: 23958
                 PAGES_READ_RATE: 0
               PAGES_CREATE_RATE: 0
              PAGES_WRITTEN_RATE: 0
                NUMBER_PAGES_GET: 3606901
                        HIT_RATE: 0
    YOUNG_MAKE_PER_THOUSAND_GETS: 0
NOT_YOUNG_MAKE_PER_THOUSAND_GETS: 0
         NUMBER_PAGES_READ_AHEAD: 768
       NUMBER_READ_AHEAD_EVICTED: 0
                 READ_AHEAD_RATE: 0
         READ_AHEAD_EVICTED_RATE: 0
                    LRU_IO_TOTAL: 0
                  LRU_IO_CURRENT: 0
                UNCOMPRESS_TOTAL: 0
              UNCOMPRESS_CURRENT: 0
8 rows in set (0.00 sec)

为了比较,SHOW ENGINE INNODB STATUS输出和INNODB缓冲池状态变量输出如下所示,基于相同的数据集。

mysql> show engine innodb status \G
......

----------------------
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 8795455488
Dictionary memory allocated 519969
Buffer pool size   524224
Free buffers       373654
Database pages     141626
Old database pages 52435
Modified db pages  0
Pending reads      0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 19074, not young 37515
0.00 youngs/s, 0.00 non-youngs/s
Pages read 6391, created 135255, written 191958
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
No buffer pool page gets since the last printout
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 141626, unzip_LRU len: 35757
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
----------------------
INDIVIDUAL BUFFER POOL INFO
----------------------
---BUFFER POOL 0
Buffer pool size   65528
Free buffers       46471
Database pages     17936
Old database pages 6640
Modified db pages  0
Pending reads      0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 16823, not young 19769
0.00 youngs/s, 0.00 non-youngs/s
Pages read 857, created 17087, written 24505
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
No buffer pool page gets since the last printout
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 17936, unzip_LRU len: 4480
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
---BUFFER POOL 1
Buffer pool size   65528
Free buffers       47000
Database pages     17515
Old database pages 6485
Modified db pages  0
Pending reads      0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 0, not young 0
0.00 youngs/s, 0.00 non-youngs/s
Pages read 864, created 16651, written 23771
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
No buffer pool page gets since the last printout
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 17515, unzip_LRU len: 4051
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
---BUFFER POOL 2
Buffer pool size   65528
Free buffers       46659
Database pages     17733
Old database pages 6565
Modified db pages  0
Pending reads      0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 0, not young 0
0.00 youngs/s, 0.00 non-youngs/s
Pages read 755, created 16978, written 23908
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
No buffer pool page gets since the last printout
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 17733, unzip_LRU len: 4544
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
---BUFFER POOL 3
Buffer pool size   65528
Free buffers       46644
Database pages     17751
Old database pages 6572
Modified db pages  0
Pending reads      0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 2251, not young 17746
0.00 youngs/s, 0.00 non-youngs/s
Pages read 802, created 16961, written 23848
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
No buffer pool page gets since the last printout
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 17751, unzip_LRU len: 4528
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
---BUFFER POOL 4
Buffer pool size   65528
Free buffers       46660
Database pages     17729
Old database pages 6564
Modified db pages  0
Pending reads      0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 0, not young 0
0.00 youngs/s, 0.00 non-youngs/s
Pages read 792, created 16937, written 24222
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
No buffer pool page gets since the last printout
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 17729, unzip_LRU len: 4550
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
---BUFFER POOL 5
Buffer pool size   65528
Free buffers       46748
Database pages     17642
Old database pages 6532
Modified db pages  0
Pending reads      0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 0, not young 0
0.00 youngs/s, 0.00 non-youngs/s
Pages read 790, created 16852, written 23741
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
No buffer pool page gets since the last printout
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 17642, unzip_LRU len: 4548
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
---BUFFER POOL 6
Buffer pool size   65528
Free buffers       46821
Database pages     17571
Old database pages 6506
Modified db pages  0
Pending reads      0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 0, not young 0
0.00 youngs/s, 0.00 non-youngs/s
Pages read 727, created 16844, written 24005
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
No buffer pool page gets since the last printout
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 17571, unzip_LRU len: 4544
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
---BUFFER POOL 7
Buffer pool size   65528
Free buffers       46651
Database pages     17749
Old database pages 6571
Modified db pages  0
Pending reads      0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 0, not young 0
0.00 youngs/s, 0.00 non-youngs/s
Pages read 804, created 16945, written 23958
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
No buffer pool page gets since the last printout
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 17749, unzip_LRU len: 4512
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
......


mysql> show status like 'Innodb_buffer%';
+---------------------------------------+--------------------------------------------------+
| Variable_name                         | Value                                            |
+---------------------------------------+--------------------------------------------------+
| Innodb_buffer_pool_dump_status        | Dumping of buffer pool not started               |
| Innodb_buffer_pool_load_status        | Buffer pool(s) load completed at 230510  9:02:54 |
| Innodb_buffer_pool_resize_status      |                                                  |
| Innodb_buffer_pool_pages_data         | 141626                                           |
| Innodb_buffer_pool_bytes_data         | 2466910208                                       |
| Innodb_buffer_pool_pages_dirty        | 0                                                |
| Innodb_buffer_pool_bytes_dirty        | 0                                                |
| Innodb_buffer_pool_pages_flushed      | 154983                                           |
| Innodb_buffer_pool_pages_free         | 373654                                           |
| Innodb_buffer_pool_pages_misc         | 8944                                             |
| Innodb_buffer_pool_pages_total        | 524224                                           |
| Innodb_buffer_pool_read_ahead_rnd     | 0                                                |
| Innodb_buffer_pool_read_ahead         | 6016                                             |
| Innodb_buffer_pool_read_ahead_evicted | 0                                                |
| Innodb_buffer_pool_read_requests      | 31733470                                         |
| Innodb_buffer_pool_reads              | 376                                              |
| Innodb_buffer_pool_wait_free          | 0                                                |
| Innodb_buffer_pool_write_requests     | 15535407                                         |
+---------------------------------------+--------------------------------------------------+
18 rows in set (0.01 sec)

MySQL InnoDB INFORMATION_SCHEMA全文索引表

InnoDB INFORMATION_SCHEMA全文索引表
随着MySQL 5.6.4对InnoDB表的全文索引支持的引入,以下表被添加到INFORMATION_SCHEMA数据库中:

mysql> show tables from information_schema like 'INNODB_FT%';
+-------------------------------------------+
| Tables_in_information_schema (INNODB_FT%) |
+-------------------------------------------+
| INNODB_FT_CONFIG                          |
| INNODB_FT_BEING_DELETED                   |
| INNODB_FT_DELETED                         |
| INNODB_FT_DEFAULT_STOPWORD                |
| INNODB_FT_INDEX_TABLE                     |
| INNODB_FT_INDEX_CACHE                     |
+-------------------------------------------+
6 rows in set (0.00 sec)

.INNODB_FT_CONFIG:显示关于InnoDB表的全文索引和相关处理的元数据。

.INNODB_FT_BEING_DELETED:提供INNODB_FT_DELETED表的快照,仅在使用optimizer table执行维护时使用。当OPTIMIZE TABLE运行时,INNODB_FT_BEING_DELETED表被清空,doc_id从INNODB_FT_DELETED表中移除。因为INNODB_FT_BEING_DELETED的内容的生命周期通常很短,所以该表在监控或调试方面的用途有限。

.INNODB_FT_DELETED:从InnoDB表的全文索引中删除的记录。为了避免在DML操作中对InnoDB全文索引进行昂贵的索引重组,新删除的单词的信息被单独存储,在执行文本搜索时从搜索结果中过滤,并且只有在运行OPTIMIZE TABLE时才从主搜索索引中删除。

.INNODB_FT_DEFAULT_STOPWORD:保存在创建全文索引时默认使用的停用词列表。

.INNODB_FT_INDEX_TABLE:包含用于处理全文索引的文本搜索的倒排索引的数据。

.INNODB_FT_INDEX_CACHE:包含新插入的行在全文索引中的标记信息。为了避免DML操作过程中昂贵的索引重组,新索引词的信息被单独存储,并仅在优化表运行时、服务器关闭时或缓存大小超过innodb_ft_cache_size或innodb_ft_total_cache_size定义的限制时才与主搜索索引结合。

注意:
除了INNODB_FT_DEFAULT_STOPWORD表,你必须将innodb_ft_aux_table配置变量设置为包含全文索引的表名(database_name/table_name)。否则,InnoDB的全文索引INFORMATION_SCHEMA表显示为空。

InnoDB全文索引INFORMATION_SCHEMA表
这个例子使用一个带全文索引的表来演示全文索引INFORMATION_SCHEMA表中包含的数据。
1.创建一个包含全文索引的表并插入一些数据:

mysql> create table articles (
    -> id int unsigned auto_increment not null primary key,
    -> title varchar(200),
    -> body text,
    -> fulltext (title,body)
    -> ) engine=innodb;
Query OK, 0 rows affected (0.05 sec)

mysql> insert into articles (title,body) values
    -> ('MySQL Tutorial','DBMS stands for DataBase ...'),
    -> ('How To Use MySQL Well','After you went through a ...'),
    -> ('Optimizing MySQL','In this tutorial we will show ...'),
    -> ('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'),
    -> ('MySQL vs. YourSQL','In the following database comparison ...'),
    -> ('MySQL Security','When configured properly, MySQL ...');
Query OK, 6 rows affected (0.01 sec)
Records: 6  Duplicates: 0  Warnings: 0

2.设置innodb_ft_aux_table变量为FULLTEXT索引表的名称。如果没有设置这个变量,除了INNODB_FT_DEFAULT_STOPWORD表之外,InnoDB的FULLTEXT INFORMATION_SCHEMA表将显示为空。

mysql> set global innodb_ft_aux_table = 'test/articles';
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like '%aux_table%';
+---------------------+---------------+
| Variable_name       | Value         |
+---------------------+---------------+
| innodb_ft_aux_table | test/articles |
+---------------------+---------------+
1 row in set (0.01 sec)

3.查询INNODB_FT_INDEX_CACHE表,它显示了在全文索引中新插入的行信息。为了避免DML操作期间昂贵的索引重组,新插入行的数据将保留在全文索引缓存中,直到优化表运行(或直到服务器关闭或超过缓存限制)。

mysql> select * from information_schema.innodb_ft_index_cache limit 5;
+------------+--------------+-------------+-----------+--------+----------+
| WORD       | FIRST_DOC_ID | LAST_DOC_ID | DOC_COUNT | DOC_ID | POSITION |
+------------+--------------+-------------+-----------+--------+----------+
| 1001       |            5 |           5 |         1 |      5 |        0 |
| after      |            3 |           3 |         1 |      3 |       22 |
| comparison |            6 |           6 |         1 |      6 |       44 |
| configured |            7 |           7 |         1 |      7 |       20 |
| database   |            2 |           6 |         2 |      2 |       31 |
+------------+--------------+-------------+-----------+--------+----------+
5 rows in set (0.00 sec)

4.启用innodb_optimize_fulltext_only,在包含全文索引的表上运行OPTIMIZE TABLE。此操作将全文索引缓存的内容刷新到主全文索引。innodb_optimize_fulltext_only改变了optimize_table语句在InnoDB表上的操作方式,并且是在对带有全文索引的InnoDB表进行维护操作时临时启用的。

mysql> SET GLOBAL innodb_optimize_fulltext_only=ON;
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like 'innodb_optimize_fulltext_only';
+-------------------------------+-------+
| Variable_name                 | Value |
+-------------------------------+-------+
| innodb_optimize_fulltext_only | ON    |
+-------------------------------+-------+
1 row in set (0.01 sec)


mysql> optimize table articles;
+---------------+----------+----------+----------+
| Table         | Op       | Msg_type | Msg_text |
+---------------+----------+----------+----------+
| test.articles | optimize | status   | OK       |
+---------------+----------+----------+----------+
1 row in set (0.01 sec)

5.查询INNODB_FT_INDEX_TABLE表,查看主要全文索引中的数据信息,包括刚刚从全文索引缓存中刷新的数据信息。

mysql> select * from information_schema.innodb_ft_index_table limit 5;
+------------+--------------+-------------+-----------+--------+----------+
| WORD       | FIRST_DOC_ID | LAST_DOC_ID | DOC_COUNT | DOC_ID | POSITION |
+------------+--------------+-------------+-----------+--------+----------+
| 1001       |            5 |           5 |         1 |      5 |        0 |
| after      |            3 |           3 |         1 |      3 |       22 |
| comparison |            6 |           6 |         1 |      6 |       44 |
| configured |            7 |           7 |         1 |      7 |       20 |
| database   |            2 |           6 |         2 |      2 |       31 |
+------------+--------------+-------------+-----------+--------+----------+
5 rows in set (0.00 sec)

INNODB_FT_INDEX_CACHE表现在是空的,因为优化表操作刷新了全文索引缓存。

mysql> select * from information_schema.innodb_ft_index_cache limit 5;
Empty set (0.00 sec)

6.从test/articles表中删除一些记录。

mysql> delete from test.articles where id < 4;
Query OK, 3 rows affected (0.01 sec)

7.查询INNODB_FT_DELETED表。该表记录从全文索引中删除的行。为了避免DML操作期间昂贵的索引重组,新删除记录的信息被单独存储,在进行文本搜索时从搜索结果中过滤,在运行OPTIMIZE TABLE时从主搜索索引中删除。

mysql> select * from information_schema.innodb_ft_deleted;
+--------+
| DOC_ID |
+--------+
|      2 |
|      3 |
|      4 |
+--------+
3 rows in set (0.01 sec)

8.运行OPTIMIZE TABLE删除删除的记录。

mysql> optimize table articles;
+---------------+----------+----------+----------+
| Table         | Op       | Msg_type | Msg_text |
+---------------+----------+----------+----------+
| test.articles | optimize | status   | OK       |
+---------------+----------+----------+----------+
1 row in set (0.03 sec)

INNODB_FT_DELETED表现在应该是空的。

mysql> select * from information_schema.innodb_ft_deleted;
Empty set (0.00 sec)

9.查询INNODB_FT_CONFIG表。该表包含关于全文索引和相关处理的元数据:
.optimize_checkpoint_limit是optimize table运行结束的秒数。

.synced_doc_id是下一个要发布的DOC_ID。

.stopword_table_name是用户定义的停止词表的数据库/表名。如果没有用户定义的停用词表,该字段显示为空。

.use_stopword表示是否使用stopword表,stopword表在创建FULLTEXT索引时定义。

mysql> select * from information_schema.innodb_ft_config;
+---------------------------+-------+
| KEY                       | VALUE |
+---------------------------+-------+
| optimize_checkpoint_limit | 180   |
| synced_doc_id             | 8     |
| stopword_table_name       |       |
| use_stopword              | 1     |
+---------------------------+-------+
4 rows in set (0.00 sec)

MySQL InnoDB INFORMATION_SCHEMA系统表

InnoDB INFORMATION_SCHEMA系统表
你可以使用InnoDB INFORMATION_SCHEMA系统表来提取由InnoDB管理的schema对象的元数据。这些信息来自InnoDB内部的系统表(也称为InnoDB数据字典),它不能像普通的InnoDB表那样直接查询。传统上,你可以使用InnoDB监视器技术来获取这类信息,设置InnoDB监视器并解析SHOW ENGINE InnoDB STATUS语句的输出。InnoDB INFORMATION_SCHEMA表接口允许你使用SQL查询这些数据。

除了INNODB_SYS_TABLESTATS没有对应的内部系统表外,InnoDB INFORMATION_SCHEMA系统表中的数据都是直接从InnoDB内部系统表中读取的,而不是从内存中缓存的元数据中读取。

InnoDB INFORMATION_SCHEMA系统表包括下面列出的表。INNODB_SYS_DATAFILES和INNODB_SYS_TABLESPACES是在MySQL 5.6.6中添加的,引入了对CREATE TABLE语句中的DATA DIRECTORY=’ DIRECTORY ‘子句的支持,它允许InnoDB file-per-table表空间(在MySQL数据目录之外的位置创建ibd文件。

mysql> SHOW TABLES FROM INFORMATION_SCHEMA LIKE 'INNODB_SYS%';
+--------------------------------------------+
| Tables_in_information_schema (INNODB_SYS%) |
+--------------------------------------------+
| INNODB_SYS_DATAFILES                       |
| INNODB_SYS_VIRTUAL                         |
| INNODB_SYS_INDEXES                         |
| INNODB_SYS_TABLES                          |
| INNODB_SYS_FIELDS                          |
| INNODB_SYS_TABLESPACES                     |
| INNODB_SYS_FOREIGN_COLS                    |
| INNODB_SYS_COLUMNS                         |
| INNODB_SYS_FOREIGN                         |
| INNODB_SYS_TABLESTATS                      |
+--------------------------------------------+
10 rows in set (0.00 sec)

表名表明所提供的数据类型:
.INNODB_SYS_TABLES提供关于InnoDB表的元数据,等价于InnoDB数据字典中的SYS_TABLES表中的信息。

.INNODB_SYS_COLUMNS提供关于InnoDB表列的元数据,等价于InnoDB数据字典中的SYS_COLUMNS表中的信息。

.INNODB_SYS_INDEXES提供有关InnoDB索引的元数据,等价于InnoDB数据字典中的SYS_INDEXES表中的信息。

.INNODB_SYS_FIELDS提供了InnoDB索引中关键列(字段)的元数据,等价于InnoDB数据字典中的SYS_FIELDS表中的信息。

.INNODB_SYS_TABLESTATS提供了关于InnoDB表的底层状态信息的视图,这些状态信息来源于内存中的数据结构。没有对应的内部InnoDB系统表。

.INNODB_SYS_DATAFILES提供了InnoDB file-per-table件和一般表空间的数据文件路径信息,等价于InnoDB数据字典中的SYS_DATAFILES表中的信息。

.INNODB_SYS_TABLESPACES提供了关于InnoDB file-per-table和一般表空间的元数据,等价于InnoDB数据字典中的SYS_TABLESPACES表中的信息。

.INNODB_SYS_FOREIGN提供了定义在InnoDB表上的外键的元数据,等价于InnoDB数据字典中的SYS_FOREIGN表中的信息。

.INNODB_SYS_FOREIGN_COLS提供了定义在InnoDB表中的外键列的元数据,等价于InnoDB数据字典中的SYS_FOREIGN_COLS表中的信息。

InnoDB INFORMATION_SCHEMA系统表可以通过TABLE_ID、INDEX_ID和SPACE等字段连接在一起,让你可以轻松地检索到你想要研究或监控的对象的所有可用数据。

这个例子使用一个简单的表(t1)和一个索引(i1)来展示在InnoDB INFORMATION_SCHEMA系统表中发现的元数据的类型。
1.创建表t1:

mysql> use test;
Database changed
mysql> create table t1 (
    -> col1 int,
    -> col2 char(10),
    -> col3 varchar(10))
    -> engine = innodb;
Query OK, 0 rows affected (0.04 sec)

mysql> create index i1 on t1(col1);
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

2.创建表t1后,查询innodb_sys_tables来定位test/t1的元数据:

mysql> select * from information_schema.innodb_sys_tables where name='test/t1' \G
*************************** 1. row ***************************
     TABLE_ID: 509
         NAME: test/t1
         FLAG: 33
       N_COLS: 6
        SPACE: 508
  FILE_FORMAT: Barracuda
   ROW_FORMAT: Dynamic
ZIP_PAGE_SIZE: 0
   SPACE_TYPE: Single
1 row in set (0.01 sec)

表t1的TABLE_ID是509。FLAG字段提供了有关表格式和存储特性的位级别信息。有6列,其中3列是由InnoDB创建的隐藏列(DB_ROW_ID, DB_TRX_ID和DB_ROLL_PTR)。表空间的ID是508(值为0表示表驻留在system表空间中)。FILE_FORMAT是Barracuda格式,ROW_FORMAT是Dynamic格式。ZIP_PAGE_SIZE只适用于行格式压缩的表。

3.使用innodb_sys_tables中的table_id信息,查询innodb_sys_columns表中关于表的列的信息。

mysql> select * from information_schema.innodb_sys_columns where table_id = 509 \G
*************************** 1. row ***************************
TABLE_ID: 509
    NAME: col1
     POS: 0
   MTYPE: 6
  PRTYPE: 1027
     LEN: 4
*************************** 2. row ***************************
TABLE_ID: 509
    NAME: col2
     POS: 1
   MTYPE: 13
  PRTYPE: 2949374
     LEN: 40
*************************** 3. row ***************************
TABLE_ID: 509
    NAME: col3
     POS: 2
   MTYPE: 12
  PRTYPE: 2949135
     LEN: 40
3 rows in set (0.00 sec)

除了TABLE_ID和NAME列之外,INNODB_SYS_COLUMNS还提供了每列的序号位置(POS)(从0开始,顺序递增),列的MTYPE或“主类型”(6 = INT,13 = CHAR, 12 = VARCHAR), PRTYPE或“精确类型”(一个二进制值,用比特表示MySQL的数据类型,字符集代码和可空性),以及列的长度(LEN)。

4.再次使用innodb_sys_tables中的table_id信息,查询innodb_sys_indexes,获取与表t1相关的索引信息。

mysql> select * from information_schema.innodb_sys_indexes where table_id = 509 \G
*************************** 1. row ***************************
       INDEX_ID: 758
           NAME: GEN_CLUST_INDEX
       TABLE_ID: 509
           TYPE: 1
       N_FIELDS: 0
        PAGE_NO: 3
          SPACE: 508
MERGE_THRESHOLD: 50
*************************** 2. row ***************************
       INDEX_ID: 759
           NAME: i1
       TABLE_ID: 509
           TYPE: 0
       N_FIELDS: 1
        PAGE_NO: 4
          SPACE: 508
MERGE_THRESHOLD: 50
2 rows in set (0.01 sec)

INNODB_SYS_INDEXES返回两个索引的数据第一个索引是GEN_CLUST_INDEX,如果表没有用户定义的聚集索引,它是由InnoDB创建的聚集索引。第二个索引(i1)是用户定义的辅助索引。

INDEX_ID是索引的标识符,在一个实例中的所有数据库中都是唯一的。TABLE_ID标识了索引关联的表。索引TYPE值指示索引类型(1 =集群索引,0 =辅助索引)。n_fields值是组成索引的字段数目。PAGE_NO是索引B-tree的根页号,SPACE是索引所在的表空间ID。非零值表示索引不在系统表空间中。MERGE_THRESHOLD定义索引页中数据量的百分比阈值。当删除一行或者更新操作缩短一行时,如果索引页中的数据量低于这个值(默认值为50%),InnoDB会尝试将索引页与相邻的索引页合并。

5.使用innodb_sys_indexes中的index_id信息,查询innodb_sys_fields中索引i1的字段信息。

mysql> select * from information_schema.innodb_sys_fields where index_id = 759 \G
*************************** 1. row ***************************
INDEX_ID: 759
    NAME: col1
     POS: 0
1 row in set (0.01 sec)

INNODB_SYS_FIELDS提供了索引字段的名称及其在索引中的序号位置。如果索引(i1)定义在多个字段上,INNODB_SYS_FIELDS将为每个被索引的字段提供元数据。

6.使用innodb_sys_tables中的space信息,查询innodb_sys_tables]表获得关于表的表空间信息。

mysql> select * from information_schema.innodb_sys_tablespaces where space = 508 \G
*************************** 1. row ***************************
         SPACE: 508
          NAME: test/t1
          FLAG: 33
   FILE_FORMAT: Barracuda
    ROW_FORMAT: Dynamic
     PAGE_SIZE: 16384
 ZIP_PAGE_SIZE: 0
    SPACE_TYPE: Single
 FS_BLOCK_SIZE: 4096
     FILE_SIZE: 114688
ALLOCATED_SIZE: 114688
1 row in set (0.05 sec)

除了表空间的SPACE ID和关联表的NAME之外,INNODB_SYS_TABLESPACES还提供了表空间的FLAG数据,这是有关表空间格式和存储特性的位级别信息。还提供了表空间FILE_FORMAT、ROW_FORMAT、PAGE_SIZE和其他几个表空间元数据项。

7.再次使用INNODB_SYS_TABLES中的SPACE信息,查询INNODB_SYS_DATAFILES表空间数据文件的位置。

mysql> select * from information_schema.innodb_sys_datafiles where space = 508 \G
*************************** 1. row ***************************
SPACE: 508
 PATH: ./test/t1.ibd
1 row in set (0.00 sec)

该数据文件位于MySQL的data目录下的test目录中。如果使用CREATE TABLE语句的data directory子句在MySQL数据目录之外的位置创建一个file-per-table表空间,那么表空间路径将是一个完全限定的目录路径。

8.最后一步,在表t1 (TABLE_ID = 509)中插入一行,然后查看INNODB_SYS_TABLESTATS表中的数据。MySQL优化器使用该表中的数据来计算查询InnoDB表时使用的索引。该信息来源于内存中的数据结构。没有对应的内部InnoDB系统表。

mysql> insert into t1 values(5, 'abc', 'def');
Query OK, 1 row affected (0.00 sec)

mysql> select * from information_schema.innodb_sys_tablestats where table_id = 509 \G
*************************** 1. row ***************************
         TABLE_ID: 509
             NAME: test/t1
STATS_INITIALIZED: Initialized
         NUM_ROWS: 1
 CLUST_INDEX_SIZE: 1
 OTHER_INDEX_SIZE: 1
 MODIFIED_COUNTER: 1
          AUTOINC: 0
        REF_COUNT: 2
1 row in set (0.00 sec)

STATS_INITIALIZED字段表示是否收集了表的统计信息。NUM_ROWS是表中当前估计的行数。cluster_index_size和OTHER_INDEX_SIZE字段分别报告磁盘上为表存储集群索引和辅助索引的页数。MODIFIED_COUNTER值显示了由DML操作和来自外键的级联操作修改的行数。AUTOINC值是任何基于自动递增操作的下一个数字。在表t1中没有定义autoincrement列,因此值为0。REF_COUNT值是一个计数器。当计数器变为0时,表示表元数据可以从表缓存中移除。

外键信息_schema系统表
INNODB_SYS_FOREIGN和INNODB_SYS_FOREIGN_COLS表提供了有关外键关系的数据。这个例子使用具有外键关系的父表和子表来展示在INNODB_SYS_FOREIGN和INNODB_SYS_FOREIGN_COLS表中找到的数据。

1.创建包含父表和子表的测试数据库:

mysql> create table parent (id int not null,
    -> primary key (id)) engine=innodb;
Query OK, 0 rows affected (0.03 sec)

mysql> create table child (id int, parent_id int,
    -> index par_ind (parent_id),
    -> constraint fk1
    -> foreign key (parent_id) references parent(id)
    -> on delete cascade) engine=innodb;
Query OK, 0 rows affected (0.01 sec)

2.在创建父表和子表之后,查询INNODB_SYS_FOREIGN并找到test/child和test/parent外键关系的外键数据:

mysql> select * from information_schema.innodb_sys_foreign \G
*************************** 1. row ***************************
      ID: test/fk1
FOR_NAME: test/child
REF_NAME: test/parent
  N_COLS: 1
    TYPE: 1

元数据包括外键ID (fk1),它是根据在子表上定义的约束命名的。FOR_NAME是定义外键的子表的名称。REF_NAME是父表(被引用的表)的名称。N_COLS是外键索引中的列数。TYPE是一个数值,表示提供有关外键列的附加信息的位标志。在本例中,TYPE值为1,表示为外键指定了ON DELETE CASCADE选项。有关类型值的更多信息,请参阅INNODB_SYS_FOREIGN表定义。

3.使用外键ID,查询INNODB_SYS_FOREIGN_COLS来查看这个外键对应的列的数据。

mysql> select * from information_schema.innodb_sys_foreign_cols where id = 'test/fk1' \G
*************************** 1. row ***************************
          ID: test/fk1
FOR_COL_NAME: parent_id
REF_COL_NAME: id
         POS: 0
1 row in set (0.00 sec)

FOR_COL_NAME是子表中外键列的名称,REF_COL_NAME是父表中被引用的列的名称。POS值是键字段在外键索引中的顺序位置,从0开始。

连接InnoDB INFORMATION_SCHEMA系统表
这个例子展示了连接三个InnoDB INFORMATION_SCHEMA系统表(INNODB_SYS_TABLES、INNODB_SYS_TABLESPACES和INNODB_SYS_TABLESTATS)来收集employees sample数据库中表的文件格式、行格式、页面大小和索引大小信息。

mysql> select a.name, a.file_format, a.row_format,
    -> @page_size :=
    -> if(a.row_format='compressed',
    -> b.zip_page_size, b.page_size)
    -> as page_size,
    -> round((@page_size * c.clust_index_size)
    -> /(1024*1024)) as pk_mb,
    -> round((@page_size * c.other_index_size)
    -> /(1024*1024)) as secidx_mb
    -> from information_schema.innodb_sys_tables a
    -> inner join information_schema.innodb_sys_tablespaces b on a.name = b.name
    -> inner join information_schema.innodb_sys_tablestats c on b.name = c.name
    -> where a.name like 'employees/%'
    -> order by a.name desc;
+------------------------+-------------+------------+-----------+-------+-----------+
| name                   | file_format | row_format | page_size | pk_mb | secidx_mb |
+------------------------+-------------+------------+-----------+-------+-----------+
| employees/titles       | Barracuda   | Dynamic    |     16384 |     0 |         0 |
| employees/t            | Barracuda   | Dynamic    |     16384 |     0 |         0 |
| employees/salaries     | Barracuda   | Dynamic    |     16384 |     0 |         0 |
| employees/employees    | Barracuda   | Dynamic    |     16384 |     0 |         0 |
| employees/dept_manager | Barracuda   | Dynamic    |     16384 |     0 |         0 |
| employees/dept_emp     | Barracuda   | Dynamic    |     16384 |     0 |         0 |
| employees/departments  | Barracuda   | Dynamic    |     16384 |     0 |         0 |
| employees/c            | Barracuda   | Dynamic    |     16384 |     0 |         0 |
+------------------------+-------------+------------+-----------+-------+-----------+
8 rows in set (0.05 sec)

IF()控制流函数用于处理压缩表。如果表被压缩,则使用ZIP_PAGE_SIZE而不是PAGE_SIZE计算索引大小。cluster_index_size和OTHER_INDEX_SIZE以字节为单位,它们除以1024*1024,就得到了以兆字节(MBs)为单位的索引长度。使用ROUND()函数将MB值四舍五入为0个小数空格。

Oracle 18c 使用影子表空间来管理丢失写保护

使用影子表空间来管理丢失写保护

当I/O子系统确认块写入已完成,但在持久存储中没有发生写入时,就会发生数据块丢失写入。影子丢失写保护可以防止丢失写。
.关于影子丢失写保护
当I/O子系统确认块写入的完成,即使没有发生写入,或者当块的前一个镜像覆盖了当前的镜像时,就会发生数据块丢失写. 影子丢失写保护可以防止表空间或单个数据文件的丢失写。

.为影子丢失写保护创建影子表空间
为了给影子丢失写保护创建一个影子表空间,在执行create big file tablespace语句时使用lost write protection子句。

.对数据库启用影子丢失写保护
为了对一个多租户容器数据库(CDB)或一个非CDB启用影子丢人写保护,可以执行带有enable lost write protection子句的alter database语句。为了对一个PDB启用影子丢失写失保护,可以执行带有enable lost write protection子句的alter pluggable database语句。

.对表空间和数据文件启用影子丢失写保护
可以对表空间和数据文件启用影子丢失写保护

.对数据库禁用影子丢失写保护
为了对CDB或非CDB数据库禁用影子丢失写保护,执行带有disable lost write protection子句的alter database语句。为了对一个pdb禁用丢失写保护,执行带有disable lost write protection子句的alter pluggable database语句。

.删除或暂停影子丢失写保护
可以对表空间或数据文件删除或暂停影子丢失写保护

.删除影子表空间
可以执行drop tablespace语句来删除影子表空间。如果使用带有including contents子句的drop tablespace语句,那么影子表空间连同它的内容会一起被删除。如果使用不带including contents子句的drop tablespace语句,那么在删除影子表空间之前,影子表空间的内容在存在其它影子表空间且有足够的可用空间时会被移动到其它的影子表空间中。

关于影子丢失写保护
当I/O子系统确认块写入的完成,即使没有发生写入,或者当块的前一个镜像覆盖了当前的镜像时,就会发生数据块丢失写操作。影子丢失写保护可以防止表空间或数据文件发生丢失写。

影子丢失写保护对于丢失写提供了一种快速检测和立即响应的方法。使用影子丢失写保护可以最小化数据丢失和请求修复数据库所需要的时间。

为了使用影子丢失写保护,你必须对数据库启用并创建一个或多个影子表空间。一个影子表空间是一种特殊目的的大文件表空间它只包含跟踪数据文件的系统改变号(SCNs)。可以通过使用带有lost write protection子句的create tablespace语句来创建一个影子表空间。

当一个被跟踪的数据块从磁盘被读取时,影子丢失写保护通过比较在影子表空间中数据块的SCN与将被读取的数据块最近写入的SCN来检测是否发生了丢失写。如果影子条目的SCN大于被读数据块的SCN,那么发生了丢失写。当检测到丢失写时会返回一个错误。

未检测到的丢失写可能会造成数据损坏因为不正确的数据可能被用于其它的DML事务。影子丢失写保护在使用之前检测到丢失写,以防止数据损坏。可以对特定的表空间和数据文件启用影子丢失写保护。因此,可以对你最重要的数据启用它。你不必使用它来跟踪你的所有数据。

此外,影子表空间也是灵活的。您可以将一个影子表空间替换为另一个影子表空间,以更改其配置或位置。

当影子丢失写保护被启用后,可以对正常的DML操作和SQL*Loader常规路径加载和直接路径加载启用。也可以对RMAN备份启用。RMAN备份检查正在读取的块是否丢失写,如果找到这样的块,会引发错误。

在对表空间或数据文件启用影子丢失写保护之后,如果你想停止收集新的丢失写保护信息并检测丢失写可以暂停它。当影子丢失写保护被暂停之后,跟踪数据会被保存在影子表空间中,并且可以重新启用影子丢失写保护。如果对数据文件或表空间删除影子丢失写保护,那么它的跟踪数据会被删除并且不能重新使用。

可以通过执行带有lost write protection子句的alter tablespace语句来对表空间启用影子丢失写保护,执行带有lost write protection子句的alter database data_file_name语句来对数据文件启用影子丢失写保护。当对表空间启用影子丢失写保护后,表空间的所有当前和以后的数据文件都会启用影子丢失写保护。

Oracle数据库会自动对一个特定的影子表空间指派一个跟踪数据文件。你不能指定那个影子表空间使用某个特定的数据文件。影子表空间中的空间量应该至少为启用影子丢失写保护的数据文件所使用的空间的2%。

注意:
如果增加跟踪数据文件的大小,那么影子丢失写保护将试图重置影子表空间中的跟踪数据。如果没有足够的空间来跟踪所有数据,那么影子丢失写保护会向日志文件插入一条告警信息并使用它所能使用的影子空间来跟踪数据。

数据库闪回会造成任何影子丢失写保护数据被删除。在闪回之后,影子丢失写保护在重新填充时跟踪数据,并在块更新时对影子跟踪数据进行更新。

影子丢失写保护与使用DB_LOST_WRITE_PROTECT初始化参数和备用数据库配置的丢失写保护无关。

为影子丢失写保护创建影子表空间
可以使用带有lost write protection子句的create bigfile tablespace语句来为影子丢失写保护创建一个影子表空间。

一个影子表空间可以被任何启用影子丢失写保护的表空间或数据文件所使用。影子表空间的空间量至少是那些启用影子丢失写保护的数据文件大小的2%.

为了创建影子表空间,数据库的兼容级别必须至少为18.0.0或更高版本。

例如创建一个名为shadow_lwp1的影子表空间供影子丢失写保护使用

SQL> CREATE BIGFILE TABLESPACE shadow_lwp1 DATAFILE 'shadow_lwp1.df' SIZE 10M LOST WRITE PROTECTION;

Tablespace created.

对数据库启用影子丢失写保护
为了对一个CDB或非CDB启用影子丢失写保护,执行带有enable lost write protection子句的alter database语句。为了对pdb启用影子丢失写保护执行带有enable lost write protection子句的alter pluggable database语句。

在对单个表空间和数据文件启用影子丢失写保护之前,你必须至少创建一个影子表空间,并且必须对包含它的数据库启用影子丢失写保护。在执行这些配置后,可以通过执行alter tablespace语句来对表空间启用影子丢失写保护,并且可以通过执行alter database语句来为数据文件启用影子丢失写保护。

注意:
对数据库启用影子丢失写保护,那么数据库的兼容级别至少为18.0.0或更高版本,并且至少存在一个影子表空间。

对CDB root启用或禁用影子丢失写保护不影响PDBs的影子丢失写保护。因此即使对CDB root禁用了影子丢失写保护也还是能对PDB启用影子丢失写保护。

当对数据库启用影子丢失写保护时,会自动指派一个影子表空间供其使用。

对数据库启用影子丢失写保护操作如下:
1.通过SQL*Plus,使用有要求的权限的用户进行登录:
.对于非CDB或CDB root使用有alter database系统权限的用户进行登录。

.对于应用程序root,PDB或应用程序PDB,使用有alter pluggable database系统权限的用户进行登录。

2.执行以下操作:
.对于非CDB或CDB root,执行带有enable lost write protection子句的alter database语句。

.对于应用程序root,PDB或应用程序PDB,执行带有enable lost write protection子句的alter pluggable database语句。

对非CDB或CDB root启用影子丢失写保护

SQL> alter database enable lost write protection;

Database altered.

对PDB启用影子丢失写保护

SQL> create bigfile tablespace shadow_pdb datafile 'shadow_pdb.dbf' size 10M lost write protection;

Tablespace created.

SQL> alter pluggable database enable lost write protection;

Pluggable database altered.

对表空间和数据文件启用影子丢失写保护
为了对表空间启用影子丢失写保护,执行带有enable lost write protection子句的alter tablespace语句。为了对数据文件启用影子丢失写保护执行带有enable lost write protection子句的alter database data_file_name语句。当对一个表空间启用了影子丢失写保护,那么就是对表空间的所有数据文件启用了影子丢失写保护,并且对于向表空间增加的任何数据文件也会启用影子丢失写保护。

注意:
.为了对一个表空间或数据文件启用影子丢失写保护那么数据库中必须至少存在一个影子表空间。
.当对一个表空间或数据文件启用影子丢失写保护,那么这个影子表空间会自动被分配给它。

为了对一个表空间或数据文件启用影子丢失写保护必须满足以下条件:
1.在SQL*Plus中,使用有以下权限的用户来连接数据库:
.如果计划对一个表空间启用影子丢失写保护,那么连接用户必须有alter tablespace权限。

.如果计划对非CDB或CDB root中的数据文件启用影子丢失写保护,那么连接用户必须有alter database权限。

.如果计划对一个应用程序root,PDB或应用程序PDB中的数据文件启用影子丢失写保护,那么连接用户必须有alter pluggable database权限。

2.执行以下操作来启用影子丢失写保护:
.为了对一个表空间启用影子丢失写保护,执行带有enable lost write protection子句的alter tablespace语句。

.为了对非CDB或CDB root中的数据文件启用影子丢失写保护,执行带有enable lost write protection子句的alter database data_file_name语句。

.为了对一个应用程序root,PDB或应用程序PDB中的数据文件启用影子丢失写保护,执行带有enable lost write protection子句的alter pluggable database datafile data_file_name语句。

创建一个test表空间并启用影子丢失写保护:

SQL> create tablespace test datafile 'test01.dbf' size 10M;

Tablespace created.


SQL> alter tablespace test enable lost write protection;

Tablespace altered.

对非CDB或CDB root中的数据文件启用影子丢失写保护

SQL> create tablespace test1 datafile 'test1_01.dbf' size 10M;

Tablespace created.

SQL> alter tablespace test1 add datafile 'test1_02.dbf' size 10M;

Tablespace altered.

SQL> alter database datafile 'test1_01.dbf' enable lost write protection;

Database altered.

对一个应用程序root,PDB或应用程序PDB中的数据文件启用影子丢失写保护

SQL> alter session set container=hypdb;

Session altered.

SQL> create tablespace cs datafile 'cs01.dbf' size 10M;

Tablespace created.

SQL> alter pluggable database datafile 'cs01.dbf' enable lost write protection;

Pluggable database altered.

对数据库禁用影子丢失写保护
为了对CDB或非CDB禁用影子丢失写保护,执行带有disable lost write protection子句的alter database语句。为了对PDB禁用影子丢失写保护,执行带有disable lost write protection子句的alter pluggable database语句。

当你对一个数据库禁用影子丢失写保护后,不是这个数据库中的表空间或数据文件可以被影子丢失写保护。

注意:
.禁用影子丢失写保护不会删除现有影子表空间中的数据,但表空间中的数据不再被更新或被检查。如果想删除影子表空间中的数据,那么可以使用带有including contents子句的drop tablespace语句。

.对CDB root启用或禁用影子丢失写保护不会影响PDBs的影子丢失写保护。

为了对一个数据库禁用影子丢失写保护必须满足以下条件:
1.在SQL*Plus中,使用有以下权限的用户来连接数据库:
.在非CDB或CDB root中,那么连接用户必须有alter tablespace权限。

.在应用程序root,PDB或应用程序PDB中,那么连接用户必须有alter pluggable database权限。

2.执行以下操作来启用影子丢失写保护:
.对非CDB或CDB root,执行带有disable lost write protection子句的alter database语句。

.对应用程序root,PDB或应用程序PDB,执行带有disable lost write protection子句的alter pluggable database语句。

对非CDB或CDB root禁用影子丢失写保护

SQL> alter session set container=cdb$root;

Session altered.


SQL> alter database disable lost write protection;

Database altered.

对PDB禁用影子丢失写保护

SQL> alter session set container=hypdb;

Session altered.

SQL> alter pluggable database disable lost write protection;

Pluggable database altered.

删除或暂停影子丢失写保护
可以对表空间或数据文件删了或暂停影子丢失写保护。

当表空间或数据文件不再需要影子丢失写保护,可以选对以下操作:
.可以删除影子丢失写保护。这个操作会从影子表空间中删除表空间或数据文件的跟踪信息。这个选项也会停止对表空间或数据文件收集新的写丢失信息并且对他们的新丢失写停止检查。

.也可以暂停影子丢失写保护。停止对表空间或数据文件收集新的写丢失信息并且对他们的新丢失写停止检查。然而旧的丢失写信息仍然保留在影子表空间中。如果对表空间或数据文件重新启用影子丢失写保护,那么它们可以使用旧的丢失写信息。

当对表空间删除或暂停影子丢失写保护后,会删除影子丢失写保护或对表空间中的所有数据文件暂停影子丢失写保护。

为了对一个表空间或数据文件删除或暂停影子丢失写保护必须满足以下条件:
1.在SQL*Plus中,使用有以下权限的用户来连接数据库:
.如果计划对一个表空间删了或禁用影子丢失写保护,那么连接用户必须有alter tablespace权限。

.如果计划对非CDB或CDB root中的数据文件删除或禁用影子丢失写保护,那么连接用户必须有alter database权限。

.如果计划对一个应用程序root,PDB或应用程序PDB中的数据文件删除或禁用影子丢失写保护,那么连接用户必须有alter pluggable database权限。

2.执行以下操作来启用影子丢失写保护:
.为了对一个表空间删除或禁用影子丢失写保护,执行带有enable lost write protection或suspend lost write protection子句的alter tablespace语句。

.为了对非CDB或CDB root中的数据文件删除或禁用影子丢失写保护,执行带有enable lost write protection或suspend lost write protection 子句的alter database data_file_name语句。

.为了对一个应用程序root,PDB或应用程序PDB中的数据文件删除或禁用影子丢失写保护,执行带有enable lost write protection或suspend lost write protection子句的alter pluggable database datafile data_file_name语句。

删了表空间test的影子丢失写保护

SQL> alter session set container=cdb$root;

Session altered.

SQL> alter tablespace test remove lost write protection;

Tablespace altered.

暂停对数据文件test1_01.dbf的影子丢失写保护

SQL> alter database datafile 'test1_01.dbf' suspend lost write protection;

Database altered.

对PDB中的数据文件cs01.dbf暂停影子丢失写保护

SQL> alter session set container=hypdb;

Session altered.

SQL> alter pluggable database datafile 'cs01.dbf' suspend lost write protection;

Pluggable database altered.

删除影子表空间
可以执行drop tablespace语句来删除影子表空间。如果执行带有including contents子句的drop tablespace语句,那么在删除影子表空间的同时也会删除它的内容和数据文件。如果执行没带inclding contents子句的drop tablespace语句,那么在删除影子表空间之前,如果存在其它的影子表空间且有足够空间,它的内容会被移到另一个影子表空间中。

SQL> drop tablespace shadow_pdb including contents;

Tablespace dropped.

MySQL使用InnoDB事务和锁信息识别阻塞事务

使用InnoDB事务和锁信息识别阻塞事务
有时识别哪些事务阻塞了另一个事务是有帮助的。包含InnoDB事务和数据锁信息的表使您能够确定哪个事务正在等待另一个事务,以及正在请求哪些资源。

假设有三个会话同时运行。每个会话对应于一个MySQL线程,并依次执行一个事务。考虑当这些会话发出以下语句,但还没有提交事务时,系统的状态:

.会话a

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select a from abc for update;
select sleep(100);+---+
| a |
+---+
| 1 |
+---+
1 row in set (0.01 sec)

mysql> select sleep(100);
+------------+
| sleep(100) |
+------------+
|          0 |
+------------+
1 row in set (1 min 40.00 sec)

.会话b

mysql> select a from abc for update;

.会话c

mysql> select a from abc for update;

在这种情况下,使用以下查询来查看哪些事务正在等待,哪些事务正在阻塞它们:

mysql> SELECT
    -> r.trx_id waiting_trx_id,
    -> r.trx_mysql_thread_id waiting_thread,
    -> r.trx_query waiting_query,
    -> b.trx_id blocking_trx_id,
    -> b.trx_mysql_thread_id blocking_thread,
    -> b.trx_query blocking_query
    -> FROM information_schema.innodb_lock_waits w
    -> INNER JOIN information_schema.innodb_trx b
    -> ON b.trx_id = w.blocking_trx_id
    -> INNER JOIN information_schema.innodb_trx r
    -> ON r.trx_id = w.requesting_trx_id;
+----------------+----------------+------------------------------+-----------------+-----------------+------------------------------+
| waiting_trx_id | waiting_thread | waiting_query                | blocking_trx_id | blocking_thread | blocking_query               |
+----------------+----------------+------------------------------+-----------------+-----------------+------------------------------+
| 5686612        |            174 | select a from abc for update | 5686611         |             173 | select a from abc for update |
| 5686612        |            174 | select a from abc for update | 5686610         |             172 | select sleep(100)            |
| 5686611        |            173 | select a from abc for update | 5686610         |             172 | select sleep(100)            |
+----------------+----------------+------------------------------+-----------------+-----------------+------------------------------+
3 rows in set, 1 warning (0.01 sec)

或者,更简单地,使用sys schema的innodb_lock_waits视图:

mysql> SELECT
    -> waiting_trx_id,
    -> waiting_pid,
    -> waiting_query,
    -> blocking_trx_id,
    -> blocking_pid,
    -> blocking_query
    -> FROM sys.innodb_lock_waits;
+----------------+-------------+------------------------------+-----------------+--------------+------------------------------+
| waiting_trx_id | waiting_pid | waiting_query                | blocking_trx_id | blocking_pid | blocking_query               |
+----------------+-------------+------------------------------+-----------------+--------------+------------------------------+
| 5686611        |         173 | select a from abc for update | 5686610         |          172 | select sleep(100)            |
| 5686612        |         174 | select a from abc for update | 5686611         |          173 | select a from abc for update |
| 5686612        |         174 | select a from abc for update | 5686610         |          172 | select sleep(100)            |
+----------------+-------------+------------------------------+-----------------+--------------+------------------------------+
3 rows in set, 3 warnings (0.08 sec)

在上面的查询结果中,你可以通过“等待查询”或“阻塞查询”列来识别会话。如你所见:
.会话b(trx_id 568661,线程号173)和会话c(trx id 5686612,线程号174)都在等待会话a(trx id 5686610,线程号172

.会话c正等待会话b和会话a

你可以在表INNODB_TRX、INNODB_LOCKS和INNODB_LOCK_WAITS中看到底层的数据。

下表是INFORMATION_SCHEMA.INNODB_TRX的一些示例内容。

mysql> select trx_id,trx_state,trx_started,trx_requested_lock_id,trx_wait_started,trx_weight,trx_mysql_thread_id,trx_query from information_schema.innodb_trx;
+-----------------+-----------+---------------------+-----------------------+---------------------+------------+---------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+
| trx_id          | trx_state | trx_started         | trx_requested_lock_id | trx_wait_started    | trx_weight | trx_mysql_thread_id | trx_query                                                                                                                                              |
+-----------------+-----------+---------------------+-----------------------+---------------------+------------+---------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+
| 5686614         | RUNNING   | 2023-12-11 16:39:57 | NULL                  | NULL                |          2 |                 172 | select sleep(100)                                                                                                                                      |
| 5686612         | LOCK WAIT | 2023-12-11 16:07:07 | 5686612:423:3:2       | 2023-12-11 16:40:07 |          2 |                 174 | select a from abc for update                                                                                                                           |
| 5686611         | LOCK WAIT | 2023-12-11 16:07:04 | 5686611:423:3:2       | 2023-12-11 16:40:04 |          2 |                 173 | select a from abc for update                                                                                                                           |
| 421200136110592 | RUNNING   | 2023-12-11 16:07:52 | NULL                  | NULL                |          0 |                 176 | select trx_id,trx_state,trx_started,trx_requested_lock_id,trx_wait_started,trx_weight,trx_mysql_thread_id,trx_query from information_schema.innodb_trx |
+-----------------+-----------+---------------------+-----------------------+---------------------+------------+---------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+
4 rows in set (0.00 sec)

mysql> select lock_id,lock_trx_id,lock_mode,lock_type,lock_table,lock_index,lock_data from information_schema.innodb_locks;
+-----------------+-------------+-----------+-----------+--------------+------------+-----------+
| lock_id         | lock_trx_id | lock_mode | lock_type | lock_table   | lock_index | lock_data |
+-----------------+-------------+-----------+-----------+--------------+------------+-----------+
| 5686612:423:3:2 | 5686612     | X         | RECORD    | `test`.`abc` | PRIMARY    | 1         |
| 5686611:423:3:2 | 5686611     | X         | RECORD    | `test`.`abc` | PRIMARY    | 1         |
| 5686614:423:3:2 | 5686614     | X         | RECORD    | `test`.`abc` | PRIMARY    | 1         |
+-----------------+-------------+-----------+-----------+--------------+------------+-----------+
3 rows in set, 1 warning (0.00 sec)

mysql> select requesting_trx_id,requested_lock_id,blocking_trx_id,blocking_lock_id from information_schema.innodb_lock_waits;
+-------------------+-------------------+-----------------+------------------+
| requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id |
+-------------------+-------------------+-----------------+------------------+
| 5686612           | 5686612:423:3:2   | 5686611         | 5686611:423:3:2  |
| 5686612           | 5686612:423:3:2   | 5686614         | 5686614:423:3:2  |
| 5686611           | 5686611:423:3:2   | 5686614         | 5686614:423:3:2  |
+-------------------+-------------------+-----------------+------------------+
3 rows in set, 1 warning (0.00 sec)

InnoDB锁和锁等待信息

当一个事务更新表中的一行,或者用SELECT FOR UPDATE锁住它时,InnoDB会为该行建立一个锁的列表或队列。类似地,InnoDB在表上维护了一个表级锁的列表。如果第二个事务想要更新一行数据或者在不兼容的模式下锁定一个已经被前一个事务锁定的表,InnoDB会向相应的队列添加一个锁请求。为了让事务获得锁,必须删除先前进入锁队列的所有不兼容的锁请求(当持有或请求这些锁的事务提交或回滚这些锁时)。

一个事务可以对不同的行或表有任意数量的锁请求。在任何给定的时间,一个事务可以请求一个由另一个事务持有的锁,在这种情况下,它被另一个事务阻塞。请求事务必须等待持有阻塞锁的事务提交或回滚。如果事务没有等待锁,则它处于运行状态。如果事务正在等待锁,则它处于锁等待状态。(INFORMATION_SCHEMA INNODB_TRX表表示事务状态值。)

INNODB_LOCKS表为每个锁等待事务保存了一个或多个行,表示任何阻止其进行的锁请求。该表还包含一行,描述给定行或表的待决锁队列中的每个锁。INNODB_LOCK_WAITS表显示了一个事务持有的哪些锁是其他事务请求的阻塞锁。

InnoDB事务与锁信息的持久化与一致性
由事务和锁表(INNODB_TRX、INNODB_LOCKS和INNODB_LOCK_WAITS)暴露的数据代表了快速变化的数据。这与用户表不同,用户表中的数据只有在应用程序发起更新时才会发生变化。底层数据是内部系统管理的数据,可以非常快速地更改。

出于性能方面的原因,以及为了尽量减少事务和锁定表之间的误导性连接,每当发出对任何表的SELECT请求时,InnoDB都会将所需的事务和锁定信息收集到中间缓冲区中。仅当从上一次读取缓冲区以来已经超过0.1秒时,才会刷新该缓冲区。填充这三张表所需的数据以原子性和一致性的方式获取,并保存在这个全局内部缓冲区中,形成一个即时点的“快照”。如果在0.1秒内发生多次表访问(当MySQL处理这些表之间的联结时,几乎肯定会发生这种情况),则使用相同的快照来满足查询。

当您将这些表中的任何一张联结到一个查询中时,都会返回正确的结果,因为这三张表的数据来自同一个快照。因为对这些表的每次查询都不会刷新缓冲区,如果您在十分之一秒内对这些表发出单独的查询,那么每次查询的结果都是相同的。另一方面,如果两次对相同或不同表的单独查询间隔超过十分之一秒,可能会得到不同的结果,因为数据来自不同的快照。

因为在收集事务和锁定数据时,InnoDB必须暂时停止,对这些表过于频繁的查询可能会对其他用户的性能产生负面影响。

因为这些表包含敏感信息(至少INNODB_LOCKS.LOCK_DATA和INNODB_TRX.TRX_QUERY),出于安全考虑,只有具有进程权限的用户才能从中选择。

如前所述,填充事务和锁表(INNODB_TRX, INNODB_LOCKS和INNODB_LOCK_WAITS)的数据会被自动获取并保存到一个提供“时间点”快照的中间缓冲区中。当从同一个快照中查询时,所有三个表的数据是一致的。然而,底层数据变化如此之快,以至于其他类似的快速变化的数据可能并不同步。因此,在比较InnoDB事务和锁定表中的数据与PROCESSLIST表中的数据时,你应该小心。PROCESSLIST表中的数据与锁定和事务的数据并不来自同一个快照。即使你只执行了一个SELECT操作(例如,关联INNODB_TRX和PROCESSLIST),这些表的内容通常也不一致。INNODB_TRX可以引用PROCESSLIST中不存在的行,或者INNODB_TRX中显示的当前正在执行的事务的SQL查询。TRX_QUERY可能与PROCESSLIST.INFO中的不同。

MySQL InnoDB与联机DDL

InnoDB与联机DDL
InnoDB联机DDL特性允许就地表更改或并发DML,或两者兼而有之。这个特性的好处包括:
.改进了繁忙的生产环境中的响应性和可用性,在这些环境中,使表在几分钟或几小时内不可用是不现实的。

.使用LOCK子句在DDL操作期间调整性能和并发性之间的平衡的能力。
.LOCK=EXCLUSIVE完全阻塞对表的访问

.LOCK=SHARED允许查询,但不允许DML。

.LOCK=NONE允许对表进行完整的查询和DML访问。

.LOCK=DEFAULT或省略LOCK子句允许尽可能多的并发,具体取决于DDL操作的类型。

.避免了与复制表和重建二级索引相关的磁盘空间使用和I/O开销。

联机DDL概述
联机DDL特性增强了许多DDL操作,这些操作以前需要表复制或阻塞表上的DML操作,或者两者兼而有之。除了大多数ALTER TABLE分区子句之外,分区后的InnoDB表的在线DDL操作遵循与普通InnoDB表相同的规则。一些因素会影响在线DDL操作的性能、空间使用和语义。
.”In-Place?”列显示哪些操作允许使用ALGORITHM=INPLACE子句。

.”Rebuilds Table?”列显示重建表的操作。对于使用INPLACE算法的操作,将就地重建表。对于不支持INPLACE算法的操作,使用表复制方法重建表。

.”Permits Concurrent DML?”列显示哪些操作是完全在线执行的。您可以指定LOCK=NONE来断言在DDL操作期间允许并发DML。MySQL在可能的情况下自动允许并发DML。

在所有在线DDL操作期间都允许并发查询。可以指定LOCK=SHARED来断言在DDL操作期间允许并发查询。MySQL在可能的情况下自动允许并发查询。

.“Notes”列提供额外的信息,并解释与其他列的“Yes/No”值相关的异常和依赖关系。星号表示异常或依赖。

下面的小节提供了各种在线DDL操作的基本语法和用法说明。
添加或删除二级索引
.添加二级索引:

CREATE INDEX name ON table (col_list);

ALTER TABLE table ADD INDEX name (col_list);

.删除二级索引:

DROP INDEX name ON table;

ALTER TABLE table DROP INDEX name;

尽管在CREATE INDEX或DROP INDEX命令中不需要更改语法,但有一些因素会影响此操作的性能、空间使用和语义。

在InnoDB表上创建和删除二级索引会跳过表复制行为。

在创建或删除索引时,表仍然可用于读写操作。CREATE INDEX或DROP INDEX语句仅在所有访问表的事务完成后才完成,因此索引的初始状态反映了表的最新内容。以前,在创建或删除索引时修改表通常会导致死锁,从而取消表上的INSERT、UPDATE或DELETE语句。

在线DDL支持添加二级索引,这意味着通常可以加快创建和加载表及其关联索引的整体过程,方法是创建不带任何二级索引的表,然后在加载数据后添加二级索引。

修改列属性
.修改列的默认值:

ALTER TABLE tbl ALTER COLUMN col SET DEFAULT literal;
ALTER TABLE tbl ALTER COLUMN col DROP DEFAULT;

列的默认值存储在表的.frm文件中,而不是InnoDB数据字典中。

.更改列的自动增量值:
ALTER TABLE table AUTO_INCREMENT=next_value;

特别是在使用复制或分片的分布式系统中,有时需要将表的自动递增计数器重置为特定值。插入到表中的下一行使用指定的值作为其自动递增列。您也可以在数据仓库环境中使用此技术,您可以定期清空所有表并重新加载它们,并且可以从1重新启动自动递增序列。

.重命名列
ALTER TABLE tbl CHANGE old_col_name new_col_name datatype;

当您保持相同的数据类型和[NOT] NULL属性时,仅更改列名,此操作始终可以在线执行。

还可以重命名属于外键约束的列。外键定义会自动更新,以使用新的列名。重命名参与外键的列仅适用于ALTER TABLE的in-place模式。如果使用了ALGORITHM=COPY子句,或者其他条件导致命令在后台使用了ALGORITHM=COPY,那么ALTER TABLE语句就会失败。

.使用in-place ALTER TABLE语句扩展VARCHAR的大小:
ALTER TABLE t13 ALGORITHM=INPLACE, CHANGE COLUMN c1 c1 VARCHAR(50);

VARCHAR列所需的长度字节数必须保持不变。对于0到255的VARCHAR值,需要一个长度字节来编码该值。对于256字节或更多的VARCHAR值,需要两个长度字节。因此,in-place ALTER TABLE只支持将VARCHAR大小从0增加到255字节,或将VARCHAR大小从等于或大于256字节的值增加。In-place ALTER TABLE不支持将VARCHAR大小从小于256字节增加到等于或大于256字节。在这种情况下,所需长度字节的数量将从1变为2,只有表复制(ALGORITHM= copy)才支持这种情况。例如,试图使用in-place ALTER TABLE将VARCHAR列的大小从255更改为256将会返回错误:

mysql> ALTER TABLE t13 ALGORITHM=INPLACE, CHANGE COLUMN c1 c1 VARCHAR(256);
ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.

mysql> ALTER TABLE t13 ALGORITHM=COPY, CHANGE COLUMN c1 c1 VARCHAR(256);
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

不支持使用in-place ALTER TABLE减少VARCHAR大小。减少VARCHAR的大小需要表的复制(ALGORITHM=COPY)。

mysql> ALTER TABLE t13 ALGORITHM=INPLACE, CHANGE COLUMN c1 c1 VARCHAR(20);
ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.

mysql> ALTER TABLE t13 ALGORITHM=COPY, CHANGE COLUMN c1 c1 VARCHAR(20);
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

添加或删除外键
.添加或删除外键约束:

ALTER TABLE tbl1 ADD CONSTRAINT fk_name FOREIGN KEY index (col1) REFERENCES tbl2(col2) referential_actions;

ALTER TABLE tbl DROP FOREIGN KEY fk_name;

删除外键可以在启用或禁用foreign_key_checks选项的情况下在线执行。在线创建外键需要禁用foreign_key_checks。

如果你不知道某张表上的外键约束的名称,执行下面的语句,并在每个外键的约束子句中找到约束名称:

SHOW CREATE TABLE table\G

或者,查询INFORMATION_SCHEMA.TABLE_CONSTRAINTS表,使用CONSTRAINT_NAME和CONSTRAINT_TYPE列来标识外键的名称。

你也可以在一条语句中删除外键及其关联索引:

ALTER TABLE table DROP FOREIGN KEY constraint, DROP INDEX index;

如果外键已经存在于被修改的表中(也就是说,它是一个包含FOREIGN KEY …REFERENCE子句的子表),其他的限制适用于在线DDL操作,即使是那些不直接涉及外键列的操作:

.如果对父表的更改通过使用CASCADE或SET NULL参数的on UPDATE或on DELETE子句引起子表的相关更改,则子表上的ALTER TABLE可以等待另一个事务提交。

.同样,如果一张表是外键关系中的父表,即使它不包含任何外键子句,如果INSERT、UPDATE或DELETE语句导致子表中的ON UPDATE或ON DELETE操作,它也可以等待ALTER TABLE完成。

维护CREATE TABLE语句
当你的数据库模式随着新列、数据类型、约束、索引等的变化而变化时,请确保CREATE TABLE语句与最新的表定义保持一致。即使有了在线DDL的性能改进,在开始时创建稳定的数据库结构比创建模式的一部分然后发出ALTER TABLE语句更有效。

对有大量行记录表的二级索引这条准则除外。通常最有效的做法是:先指定除二级索引之外的所有详细信息,然后加载数据,再创建二级索引。如果您知道初始数据是干净的,并且在加载过程中不需要一致性检查,则可以对外键使用相同的技术(首先加载数据,然后设置外键)。

无论CREATE TABLE、CREATE INDEX、ALTER TABLE和类似的语句是如何将一个表组合在一起的,您都可以通过执行语句SHOW CREATE TABLE TABLE \G(为了整洁的格式化,需要大写\G)来捕获重建表所需的SQL。上述输出显示了numeric precision、NOT NULL和CHARACTER SET等子句,这些子句有时是在后台添加的,用户可能希望在新系统上克隆表或设置相同类型的外键列时省去这些子句。

联机DDL性能、并发性和空间需求
联机DDL提高了MySQL操作的几个方面,如性能、并发性、可用性和可伸缩性:
.由于表上的查询和DML操作可以在DDL进行时继续进行,因此访问表的应用程序响应更快。在整个MySQL服务器中减少锁和等待其他资源会带来更大的可伸缩性,即使对于不涉及修改表的操作也是如此。

.对于in-place操作,通过避免重新构建表所需的磁盘I/O和CPU周期,可以最小化数据库的总体负载,并在DDL操作期间保持良好的性能和高吞吐量。

.对于in-place操作,由于读入缓冲池的数据比复制所有数据要少,因此可以避免从内存中清除频繁访问的数据,这在以前可能会在DDL操作之后导致暂时的性能下降。

如果联机操作需要临时排序文件,InnoDB默认在临时文件目录下创建它们,而不是在包含原始表的目录下。如果这个目录不够大,无法容纳这样的文件,您可能需要将tmpdir系统变量设置为另一个目录。另外,您可以使用innodb_tmpdir配置选项为InnoDB在线ALTER TABLE操作定义一个单独的临时目录。

联机DDL的锁选项
当DDL操作改变InnoDB表时,表可能被锁住,也可能不被锁住,这取决于DDL操作的内部工作原理和ALTER table语句的LOCK子句。默认情况下,MySQL在DDL操作期间使用尽可能少的锁;您可以指定这个子句,使锁定比通常情况下更加严格(从而限制并发DML或DML和查询),或者确保某个操作允许某种预期程度的锁定。如果LOCK子句指定的锁级别不适用于特定类型的DDL操作,例如在创建或删除主键时指定LOCK=SHARED或LOCK=NONE,那么该子句就会像断言一样工作,导致语句失败并报错。下面列出了LOCK子句的不同可能性,从最宽松的到最严格的:

.对于LOCK=NONE的DDL操作,查询和并发DML都是允许的。如果不能使用所请求的锁类型执行DDL操作,则该子句会使ALTER TABLE失败,因此,如果保持表完全可用是至关重要的,则指定LOCK=NONE,如果不可能则可以取消DDL。例如,您可以在DDLs中对涉及客户注册或购买的表使用此子句,以避免错误地发出昂贵的ALTER TABLE语句,从而使这些表不可用。

.对于LOCK=SHARED的DDL操作,任何对表的写操作(即DML操作)都会被阻塞,但是可以读取表中的数据。如果请求的锁类型不能执行这种DDL操作,则该子句会使ALTER TABLE失败,因此,如果保持表对查询可用非常重要,则指定LOCK=SHARED,如果不可能,则可以取消DDL。例如,您可以在DDL中为数据仓库中的表使用这个子句,在DDL中可以延迟数据加载操作直到DDL完成,但是不能长时间延迟查询。

.对于使用LOCK=DEFAULT或省略LOCK子句的DDL操作,MySQL针对此类操作使用可用的最低级别的锁,允许并发查询、DML或两者同时使用。当您根据表的工作负载进行预先计划、预先测试的更改,并且知道不会导致任何可用性问题时,将使用此设置。

.对于LOCK=EXCLUSIVE的DDL操作,查询和DML操作都被阻塞。如果请求的锁类型不能执行这种DDL操作,这个子句会使ALTER TABLE失败,因此,如果主要关注的是在尽可能短的时间内完成DDL,则指定LOCK=EXCLUSIVE,并且可以使应用程序在尝试访问表时等待。如果服务器应该是空闲的,您也可以使用LOCK=EXCLUSIVE,以避免对表的意外访问。

在大多数情况下,表上的联机DDL操作等待正在访问表的当前执行的事务提交或回滚,因为在准备DDL语句时,它需要在短时间内独占访问表。同样,联机DDL操作在完成之前需要对表进行短时间的独占访问。因此,联机DDL语句也会等待DDL正在提交或回滚时启动的事务完成。因此,对于执行插入、更新、删除的长时间运行的事务或对表执行SELECT .. FOR UPDATE操作,联机DDL操作可能会超时等待对表的独占访问。

当表处于外键关系中,并且事务在外键关系中的另一个表上显式运行时,可能发生表上的在线DDL操作不等待当前执行的事务完成的情况。在这种情况下,事务在它正在更新的表上持有一个排他的元数据锁,但只持有另一张表上共享的InnoDB表锁(外键检查所需)。共享的InnoDB表锁允许在线DDL操作继续进行,当需要一个互斥的InnoDB表锁时会在提交阶段阻塞操作。当其他事务等待在线DDL操作提交时,此场景可能导致死锁。(参见Bug #48652和Bug #77390)

因为需要一些处理工作来记录并发DML操作所做的更改,然后在最后应用这些更改,所以在线DDL操作可能比阻止其他会话访问表的旧式机制花费更长的时间。原始性能的降低与使用表的应用程序更好的响应性是平衡的。在评估更改表结构的理想技术时,要根据诸如网页加载时间等因素,考虑最终用户对性能的感知。

当CREATE INDEX或ALTER TABLE语句执行完毕时,一个新创建的InnoDB二级索引只包含表中已提交的数据。它不包含任何未提交的值、值的旧版本或标记为删除但尚未从旧索引中删除的值。

In-PlaceDDL操作与Table-Copy DDL操作的性能
在线DDL操作的原始性能在很大程度上取决于该操作是in-place执行,还是需要复制和重建整个表。

in-place DDL带来的性能提升适用于二级索引上的操作,而不是主键索引。InnoDB表中的行存储在一个基于主键组织的聚集索引中,形成了一些数据库系统所称的“索引组织表”。因为表结构与主键紧密联系在一起,所以重新定义主键仍然需要复制数据。

当对主键的操作使用ALGORITHM=INPLACE时,即使数据仍然被复制,它也比使用ALGORITHM=COPY更有效,因为:
.ALGORITHM=INPLACE不需要undo日志记录或相关的重做日志记录。这些操作增加了使用ALGORITHM=COPY的DDL语句的开销。

.二级索引项是预先排序的,因此可以按顺序加载。

.没有使用更改缓冲区,因为没有随机访问插入到二级索引中。

为了判断在线DDL操作的相对性能,你可以使用当前版本和更早版本的MySQL在一个大的InnoDB表上运行这样的操作。还可以在最新的MySQL版本下运行所有性能测试,通过设置old_alter_table系统变量,模拟“before”结果的DDL行为。在会话中发出语句set old_alter_table=1,并测量DDL性能以记录“之前”的数字。然后设置old_alter_table=0以重新启用更新、更快的行为,并再次运行DDL操作以记录“之后”的数字。

要了解DDL操作是in-place进行更改还是执行表复制的基本概念,请查看命令完成后显示的“受影响的行”值。例如,在执行不同类型的DDL操作后,您可能会看到以下行:
.更改列的默认值(超快,完全不影响表数据):

Query OK, 0 rows affected (0.07 sec)

.添加索引(需要时间,但是0行受影响表明表没有被复制):

Query OK, 0 rows affected (21.42 sec)

.更改列的数据类型(需要花费大量时间,并且需要重建表中的所有行):

Query OK, 1671168 rows affected (1 min 35.54 sec)

更改列的数据类型需要重建表中的所有行,VARCHAR大小的更改除外,这可以使用在线ALTER table执行。

例如,在一个大表上运行DDL操作之前,你可能会检查操作的快慢,如下所示:
1.克隆表结构。

2.用少量数据填充克隆表。

3.在克隆表上运行DDL操作。

4.检查“受影响的行”值是否为零。非零值意味着操作需要重建整个表,这可能需要特殊的规划。例如,您可以在计划的停机期间执行DDL操作,或者每次在每个复制从服务器上执行一个。

为了更深入地了解MySQL处理过程中的归约,可以查看DDL操作前后与InnoDB相关的performance_schema和INFORMATION_SCHEMA表,查看物理读、写、内存分配等的数量。

联机DDL操作的空间要求
联机DDL操作对空间的要求如下:
.存放临时日志文件的空间
对于每个创建的索引或修改的表,都有一个这样的日志文件。此日志文件存储在DDL操作期间在表中插入、更新或删除的数据。临时日志文件在需要时通过innodb_sort_buffer_size的值进行扩展,直到达到innodb_online_alter_log_max_size指定的最大值。如果临时日志文件的大小超过上限,那么ALTER TABLE操作将失败,所有未提交的并发DML操作将回滚。因此,如果该选项的值较大,就允许在联机DDL操作期间发生更多的DML,
但也会延长DDL操作结束时表被锁定以应用日志中的数据的时间。

如果操作花费的时间太长,并发的DML修改表的时间太长,导致临时在线日志的大小超过innodb_online_alter_log_max_size配置选项的值,则在线DDL操作失败,并出现DB_ONLINE_LOG_TOO_BIG错误。

.临时排序文件的空间
重建表的在线DDL操作在创建索引时将临时排序文件写入MySQL临时目录(Unix上为$TMPDIR, Windows上为%TEMP%,或由–tmpdir配置变量指定的目录)。每个临时排序文件都足够大,可以容纳新二级索引定义的所有列,以及聚集索引的主键的列,一旦合并到最终表或索引中,这些列就会被删除。此类操作需要的临时空间相当于存储表中数据和索引数据所需要的空间大小。如果重建表的联机DDL操作使用了数据目录(datadir)所在的文件系统上的所有可用磁盘空间,则会导致错误。

从MySQL 5.7.11开始,你可以使用innodb_tmpdir配置选项为联机DDL操作定义一个单独的临时目录。innodb_tmpdir选项的引入是为了避免在联机ALTER TABLE操作重建表时创建大型临时排序文件时可能发生的临时目录溢出。

.中间表文件的空间
一些重建表的联机DDL操作在与原始表相同的目录中创建临时中间表文件,而不是在原地重建表。中间表文件可能需要与原始表大小相等的空间。

联机DDL SQL语法
通常,当对InnoDB表使用ALTER TABLE语句时,不需要做任何特殊的事情来启用联机DDL。一些变体需要使用配置或与ALTER TABLE子句的特定组合。

通过使用ALTER TABLE语句的LOCK和ALGORITHM子句,可以控制特定联机DDL操作的各个方面。这些子句位于语句的末尾,用逗号与表和列的规范分隔。LOCK子句用于微调对表的并发访问程度。ALGORITHM子句主要用于性能比较并作为在现有DDL代码遇到任何问题时对旧表复制行为的回退。例如:
.为了避免意外地使表不可读、不可写或不可读和不可写,可以在ALTER table语句中指定一个子句,例如LOCK=NONE(允许读写)或LOCK=SHARED(允许读)。如果请求的并发级别不可用,操作将立即停止。

.为了比较性能,除了设置old_alter_table配置选项外,还可以运行一个ALGORITHM=INPLACE语句和另一个算法ALGORITHM=COPY的语句。

.为了避免复制表的ALTER TABLE操作占用服务器资源,可以使用ALGORITHM=INPLACE子名。如果不能使用in-place机制,该语句将立即停止。

使用联机DDL简化DDL语句
在引入联机DDL之前,将许多DDL操作组合到单个ALTER TABLE语句中是一种常见的做法。因为每个ALTER TABLE语句都涉及复制和重建表,所以一次对同一个表进行多次更改会更加高效,因为这些更改可以通过对表的一次重建操作完成。缺点是涉及DDL操作的SQL代码很难在不同的脚本中维护和重用。如果每次的具体更改都不同,则可能需要为每个稍有不同的场景构建一个新的复杂的ALTER TABLE。

对于可以in-place完成的DDL操作,现在,您可以将它们分离为单独的ALTER TABLE语句,以便于编写脚本和维护,而不会牺牲效率。例如,你可以用这样一个复杂的语句:

ALTER TABLE t1 ADD INDEX i1(c1), ADD UNIQUE INDEX i2(c2),
CHANGE c4_old_name c4_new_name INTEGER UNSIGNED;

将其分解为可以独立测试和执行的更简单的部分,例如:

ALTER TABLE t1 ADD INDEX i1(c1);
ALTER TABLE t1 ADD UNIQUE INDEX i2(c2);
ALTER TABLE t1 CHANGE c4_old_name c4_new_name INTEGER UNSIGNED NOT NULL;

你可能仍然要使用由多个部分组成的ALTER TABLE语句:
.必须按特定顺序执行的操作,例如创建索引,然后使用该索引的外键约束。

.所有操作都使用相同的特定LOCK子句,希望作为一个组成功或失败。

.不能in-place执行的操作,即仍然复制和重建表的操作。

.指定ALGORITHM=COPY或old_alter_table=1的操作,如果需要在特定场景中实现精确的向后兼容性,可以强制表复制行为。

联机DDL实现详细信息
InnoDB表的每个ALTER TABLE操作都受以下几个方面的控制:
.是否对表的物理表示有任何更改,或者是否纯粹是对元数据的更改,而无需触及表本身。

.表中的数据量是保持不变、增加还是减少

.表数据的更改是否涉及聚集索引、二级索引或两者。

.被修改的表与其他表之间是否存在外键关系。机制差异取决于foreign_key_checks配置选项是启用还是禁用。

.表是否被分区。ALTER TABLE的分区子句被转换为涉及一个或多个表的低级操作,这些操作遵循联机DDL的常规规则。

.是否必须复制表数据,表是否可以“in-place”重组,或者两者的组合。

.需要多大程度的锁定,取决于底层数据库操作的性质,或者取决于在ALTER TABLE语句中指定的LOCK子句。

联机DDL错误条件
以下是联机DDL操作可能失败的主要原因:
.如果LOCK子句指定了低级别锁(SHARED或NONE)将与特定类型的DDL操作不兼容。

.如果在等待获得表上的排他锁时发生超时,在DDL操作的初始和最后阶段可能需要短暂的超时。

.MySQL在创建索引时将临时排序文件写入磁盘,如果tmpdir或innodb_tmpdir文件系统耗尽了磁盘空间。

.如果ALTER TABLE花费了很长时间,并且并发的DML对表的修改太多,那么临时在线日志的大小超过了innodb_online_alter_log_max_size配置选项的值。这种情况会导致DB_ONLINE_LOG_TOO_BIG错误。

.如果并发DML对原表定义允许的表进行更改,但新表定义不允许。只有在最后,当MySQL试图应用并发DML语句中的所有更改时,操作才会失败。例如,用户可以在创建唯一索引时向列中插入重复的值,或者在创建主键索引时向列中插入NULL值。并发DML所做的更改优先,并且有效地回滚了ALTER TABLE操作。

尽管配置选项innodb_file_per_table对InnoDB表的表示有显著的影响,但是不管这个选项是启用还是禁用,不管表物理位置是在它自己的.ibd文件中还是在系统表空间中,所有的在线DDL操作都是一样的。

InnoDB有两种类型的索引:代表表中所有数据的聚集索引,以及可选的加速查询的二级索引。因为聚集索引包含其b树节点中的数据值,所以添加或删除聚集索引需要复制数据,并创建表的新副本。而二级索引只包含索引键和主键的值。可以在不复制聚集索引中的数据的情况下创建或删除这种类型的索引。因为每个二级索引都包含主键值的副本(用于在需要时访问聚集索引),所以当更改主键的定义时,也会重新创建所有二级索引。

删除二级索引很简单。只有内部的InnoDB系统表和MySQL数据字典表被更新,以反映索引不再存在的事实。InnoDB将用于索引的存储空间返回到包含它的表空间,以便新的索引或额外的表行可以使用该空间。

为了给已存在的表添加二级索引,InnoDB会扫描表,并使用内存缓冲区和临时文件,根据二级索引键列的值对行进行排序。B树是按键值顺序构建的,这比按随机顺序将行插入索引更高效。因为b树节点在填充时是分裂的,以这种方式构建索引会导致索引的填充因子更高,从而使后续访问更高效。

联机DDL和崩溃恢复
虽然在执行ALTER TABLE语句时服务器崩溃不会丢失数据,但是集群索引和二级索引的崩溃恢复过程是不同的。

如果服务器在创建InnoDB二索引时崩溃,在恢复时,MySQL删除所有部分创建的索引。您必须重新运行ALTER TABLE或CREATE INDEX语句。

当在创建InnoDB集群索引时发生崩溃时,恢复会更加复杂,因为表中的数据必须复制到一个全新的集群索引中。请记住,所有InnoDB表都存储为集群索引。

MySQL通过将原始InnoDB表中的现有数据复制到具有所需索引结构的临时表中来创建新的集群索引。一旦数据被完全复制到这个临时表中,原始表将被重命名为一个不同的临时表名。包含新聚集索引的临时表将使用原始表的名称重命名,原始表将从数据库中删除。

如果在创建新的聚集索引时发生系统崩溃,则不会丢失数据,但是必须使用该过程中存在的临时表来完成恢复过程。由于在此操作期间很少重新创建聚集索引或重新定义大型表上的主键,也很少遇到系统崩溃的情况,因此本手册不提供有关从此场景中恢复的信息。

分区表的联机DDL
大多数ALTER TABLE分区子句不会像常规的非分区InnoDB表那样使用相同的内部联机DDL API。因此,对ALTER TABLE分区子句的联机支持各不相同。

下表显示了每个ALTER TABLE分区语句的联机状态。不管使用的是哪种联机DDL API, MySQL都会尽可能地减少数据复制和锁定。
.”In-Place”列显示哪些操作允许使用ALGORITHM=INPLACE子句。

.”Permits Concurrent DML?”列显示哪些操作是完全联机执行的。您可以指定LOCK=NONE来断言在DDL操作期间允许并发DML。MySQL在可能的情况下自动允许并发DML。

对于支持ALGORITHM={COPY|INPLACE}的操作,可以指定LOCK=SHARED来断言DDL操作期间允许并发查询。MySQL在可能的情况下自动允许并发查询。

.“Notes”列提供了其他信息,并解释了与其他列的“Yes/No”值相关的异常和依赖关系。星号表示异常或依赖项。

使用ALGORITHM=COPY或只允许”ALGORITHM=DEFAULT, LOCK=DEFAULT”的ALTER TABLE分区选项,将使用COPY算法对表进行重新分区。换句话说,使用新的分区方案创建了一个新的分区表。新创建的表包含ALTER table语句应用的任何更改,表数据被复制到新的表结构中。

对分区表执行非分区联机ALTER TABLE操作遵循适用于常规表的相同规则。但是,ALTER TABLE在每个表分区上执行在线操作,由于在多个分区上执行操作,这会导致对系统资源的需求增加。

联机DDL限制
联机DDL操作存在以下限制:
.在TEMPORARY表上创建索引时复制表,而不是使用快速索引创建。这已经被报告为MySQL Bug #39833。

.当用户试图删除外键所需的索引时,InnoDB会处理错误。

.如果表上有ON…CASCADE或ON…SET NULLT约束,ALTER TABLE子句LOCK=NONE是不允许的。

.根据联机DDL操作的内部工作原理和ALTER TABLE语句的LOCK子句,联机DDL操作在DDL操作的初始阶段和最终阶段可能需要在短时间内对表进行排他访问。因此,如果有一个执行插入、更新、删除或对表执行SELECT … FOR UPDATE的长时间运行的事务并且如果在ALTER TABLE进行中启动了类似的长时间运行的事务,则联机DDL操作可能需要等待才能完成。

.当运行一个联机DDL操作时,运行ALTER TABLE语句的线程应用一个来自其他连接线程在同一个表上并发运行的DML操作的“在线日志”。当应用DML操作时,可能会遇到重复键条目错误(错误1062(23000):重复条目),即使重复条目只是临时的,并且会被“在线日志”中的稍后条目恢复。这类似于InnoDB中的外键约束检查,其中约束必须在事务期间保持。

.将InnoDB表的OPTIMIZE TABLE映射到ALTER TABLE以重建表并更新索引统计信息和释放聚集索引中的未使用空间。创建辅助索引的效率不高,因为键是按照它们在主键中出现的顺序插入的。通过添加在线DDL支持,可以重建常规的和分区的InnoDB表。

.在MySQL 5.6之前创建的InnoDB表,对于包括时间列(日期,日期时间或时间戳)的表不支持ALTER TABLE…ALGORITHM=INPLACE且不能使用ALTER TABLE…ALGORITHM=COPY进行重建。在这种情况下,ALTER TABLE…ALGORITHM=INPLACE操作返回如下错误:

ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported.
Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.

.这些限制通常适用于涉及表复制的大型表上的在线DDL操作:
.不存在暂停在线DDL操作或限制在线DDL操作的I/O或CPU使用的机制DDL操作。

.如果操作失败,回滚在线DDL操作的代价可能很高。

.长时间运行在线DDL操作可能导致复制滞后。在线DDL操作必须在主节点上运行完之后才能在从节点上运行。此外,在主服务器上并发处理的DML只有在从服务器上的DDL操作完成后才会在从服务器上处理(Bug #73196)。

MySQL InnoDB行存储和行格式

InnoDB行存储和行格式
本节讨论InnoDB的特性,如表压缩、可变长度列值的页外存储和大索引键前缀(innodb_large_prefix)是如何由InnoDB表的行格式控制的。它还讨论了选择正确行格式的注意事项,以及MySQL版本之间行格式的兼容性。

InnoDB行存储概述
行和关联列的存储影响查询和DML操作的性能。由于单个磁盘页面中容纳了更多的行,查询和索引查找可以更快地工作,InnoDB缓冲池中所需的缓存内存更少,为数字和短字符串列写更新值所需的I/O也更少。

每个InnoDB表中的数据被划分为多个页。组成每个表的页面排列在称为b-树索引的树状数据结构中。表数据和二级索引都使用这种类型的结构。表示整个表的b树索引称为聚集索引,它是根据主键列组织的。索引数据结构的节点包含该行中所有列的值(对于聚集索引)或索引列和主键列的值(对于辅助索引)。

变长列是此规则的例外。像BLOB和VARCHAR这样的列太长而不能放在b树页上,它们存储在单独分配的磁盘页上,称为溢出页。我们称这样的列为页外列。这些列的值存储在溢出页的单链表中,每个这样的列都有自己的一个或多个溢出页列表。在某些情况下,长列值的全部或前缀存储在b树中,以避免浪费存储空间并消除读取单独页面的需要。

下面的章节描述了如何配置InnoDB表的行格式来控制如何存储可变长度列的值。行格式配置还决定了表压缩特性和大索引键前缀特性(innodb_large_prefix)的可用性。

指定表的行格式
默认的行格式由innodb_default_row_format定义,默认值为DYNAMIC。当没有显式定义ROW_FORMAT表选项或指定ROW_FORMAT= default时,使用默认行格式。

mysql> show variables like 'innodb_default_row_format';
+---------------------------+---------+
| Variable_name             | Value   |
+---------------------------+---------+
| innodb_default_row_format | dynamic |
+---------------------------+---------+
1 row in set (0.02 sec)

表的行格式可以在CREATE table或ALTER table语句中使用ROW_FORMAT表选项显式定义。例如:

mysql> CREATE TABLE t9 (c1 INT) ROW_FORMAT=DYNAMIC;
Query OK, 0 rows affected (0.03 sec)

显式定义的ROW_FORMAT设置覆盖隐式默认值。指定ROW_FORMAT=DEFAULT相当于使用隐式默认值。

innodb_default_row_format选项可以动态设置:

mysql> SET GLOBAL innodb_default_row_format=DYNAMIC;

有效的innodb_default_row_format选项包括DYNAMIC、COMPACT和REDUNDANT。COMPRESSED行格式不支持在系统表空间中使用,不能被定义为默认行格式。它只能在CREATE TABLE或ALTER TABLE语句中显式指定。尝试将innodb_default_row_format设置为COMPRESSED会返回一个错误:

mysql> SET GLOBAL innodb_default_row_format=COMPRESSED;
ERROR 1231 (42000): Variable 'innodb_default_row_format' can't be set to the value of 'COMPRESSED'

当没有明确指定ROW_FORMAT选项或使用ROW_FORMAT=DEFAULT时,新创建的表使用innodb_default_row_format定义的行格式。例如,下面的CREATE TABLE语句使用innodb_default_row_format定义的行格式。

mysql> CREATE TABLE t10 (c1 INT);
Query OK, 0 rows affected (0.02 sec)

mysql> CREATE TABLE t11 (c1 INT) ROW_FORMAT=DEFAULT;
Query OK, 0 rows affected (0.01 sec)


mysql> show variables like 'innodb_default_row_format';
+---------------------------+---------+
| Variable_name             | Value   |
+---------------------------+---------+
| innodb_default_row_format | dynamic |
+---------------------------+---------+
1 row in set (0.02 sec)

mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME='undo/t10'\G
*************************** 1. row ***************************
     TABLE_ID: 498
         NAME: undo/t10
         FLAG: 33
       N_COLS: 4
        SPACE: 500
  FILE_FORMAT: Barracuda
   ROW_FORMAT: Dynamic
ZIP_PAGE_SIZE: 0
   SPACE_TYPE: Single
1 row in set (0.00 sec)

mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME='undo/t11'\G
*************************** 1. row ***************************
     TABLE_ID: 499
         NAME: undo/t11
         FLAG: 33
       N_COLS: 4
        SPACE: 501
  FILE_FORMAT: Barracuda
   ROW_FORMAT: Dynamic
ZIP_PAGE_SIZE: 0
   SPACE_TYPE: Single
1 row in set (0.00 sec)

当没有显式指定ROW_FORMAT选项或使用ROW_FORMAT=DEFAULT时,任何重建表的操作都会将表的行格式静默地更改为innodb_default_row_format定义的格式。

表重建操作包括使用ALGORITHM=COPY的ALTER TABLE操作和使用ALGORITHM= INPLACE的ALTER TABLE操作。OPTIMIZE TABLE也是一个表重建操作。

下面的示例演示了一个表重建操作,该操作静默地更改在没有显式定义行格式的情况下创建的表的行格式。

mysql> SELECT @@innodb_default_row_format;
+-----------------------------+
| @@innodb_default_row_format |
+-----------------------------+
| dynamic                     |
+-----------------------------+
1 row in set (0.00 sec)

mysql> CREATE TABLE t12 (c1 INT);
Query OK, 0 rows affected (0.01 sec)

mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE 'undo/t12' \G
*************************** 1. row ***************************
     TABLE_ID: 500
         NAME: undo/t12
         FLAG: 33
       N_COLS: 4
        SPACE: 502
  FILE_FORMAT: Barracuda
   ROW_FORMAT: Dynamic
ZIP_PAGE_SIZE: 0
   SPACE_TYPE: Single
1 row in set (0.01 sec)

mysql> SET GLOBAL innodb_default_row_format=COMPACT;
Query OK, 0 rows affected (0.00 sec)

mysql> ALTER TABLE t12 ADD COLUMN (c2 INT);
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE 'undo/t12' \G
*************************** 1. row ***************************
     TABLE_ID: 501
         NAME: undo/t12
         FLAG: 1
       N_COLS: 5
        SPACE: 503
  FILE_FORMAT: Antelope
   ROW_FORMAT: Compact
ZIP_PAGE_SIZE: 0
   SPACE_TYPE: Single
1 row in set (0.00 sec)

在将现有表的行格式从REDUNDANT或COMPACT更改为DYNAMIC之前,请考虑以下潜在问题。
.如果启用了innodb_large_prefix配置选项,则REDUNDANT和COMPACT行格式支持的最大索引键前缀长度为767字节,而DYNAMIC和COMPRESSED行格式支持的索引键前缀长度为3072字节。在复制环境中,如果innodb_default_row_format在主服务器上被设置为DYNAMIC,在从服务器上被设置为COMPACT,那么下面的DDL语句(没有明确定义行格式)在主服务器上成功,在从服务器上失败:

CREATE TABLE t1 (c1 INT PRIMARY KEY, c2 VARCHAR(5000), KEY i1(c2(3070)));

.导入一个没有显式定义行格式的表,如果源服务器上的innodb_default_row_format设置与目标服务器上的设置不同,则会导致模式不匹配错误。

要查看表的行格式,可以发出SHOW TABLE STATUS语句或查询INFORMATION_SCHEMA.TABLES。

mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE 'undo/t12' \G
*************************** 1. row ***************************
     TABLE_ID: 501
         NAME: undo/t12
         FLAG: 1
       N_COLS: 5
        SPACE: 503
  FILE_FORMAT: Antelope
   ROW_FORMAT: Compact
ZIP_PAGE_SIZE: 0
   SPACE_TYPE: Single
1 row in set (0.00 sec)

mysql> SHOW TABLE STATUS\G
*************************** 1. row ***************************
           Name: big_table
         Engine: InnoDB
        Version: 10
     Row_format: Dynamic
           Rows: 3370592
 Avg_row_length: 205
    Data_length: 694140928
Max_data_length: 0
   Index_length: 0
      Data_free: 3145728
 Auto_increment: 3326977
    Create_time: 2023-07-06 18:05:18
    Update_time: NULL
     Check_time: NULL
      Collation: utf8mb4_general_ci
       Checksum: NULL
 Create_options:
        Comment:

InnoDB表的行格式决定了它的物理行结构。

DYNAMIC和COMPRESSED行格式
当创建一个ROW_FORMAT=DYNAMIC或ROW_FORMAT=COMPRESSED的表时,InnoDB可以存储长可变长度的列值(对于VARCHAR, VARBINARY, BLOB和TEXT类型)完全溢出页,集群索引记录只包含一个指向溢出页的20字节指针。InnoDB也将长度大于或等于768字节的固定长度字段编码为可变长度字段。例如,如果字符集的最大字节长度大于3,那么CHAR(255)列可以超过768字节,就像utf8mb4一样。

是否有列存储在页外取决于页大小和行的总大小。当行太长时,InnoDB选择最长的列作为页外存储,直到聚集索引记录适合B-tree页。小于或等于40字节的TEXT和BLOB列始终内联存储。

如果适合的话,DYNAMIC行格式保持了在索引节点中存储整行的效率(就像COMPACT和REDUNDANT格式一样),但是DYNAMIC行格式避免了用长列的大量数据字节填充b树节点的问题。DYNAMIC格式基于这样的思想:如果长数据值的一部分存储在页外,那么将所有值存储在页外通常是最有效的。使用DYNAMIC格式,较短的列可能会保留在B-tree节点中,从而最大限度地减少任何给定行所需的溢出页数。

对于页外存储,COMPRESSED行格式使用了与DYNAMIC行格式类似的内部细节,同时对表和索引数据进行了额外的存储和性能考虑,并使用了更小的页面大小。对于COMPRESSED行格式,KEY_BLOCK_SIZE选项控制在聚集索引中存储多少列数据,以及在溢出页上放置多少列数据。

DYNAMIC和COMPRESSED行格式都支持最多3072字节的索引键前缀。该特性由innodb_large_prefix配置选项控制,默认情况下是启用的。

mysql> select @@innodb_large_prefix;
+-----------------------+
| @@innodb_large_prefix |
+-----------------------+
|                     1 |
+-----------------------+
1 row in set (0.00 sec)

mysql> show variables like 'innodb_large_prefix';
+---------------------+-------+
| Variable_name       | Value |
+---------------------+-------+
| innodb_large_prefix | ON    |
+---------------------+-------+
1 row in set (0.01 sec)

使用COMPRESSED行格式的表可以在file-per-table表空间或一般表空间中创建。system表空间不支持COMPRESSED行格式。为了在file-per-table表空间中存储压缩表,innodb_file_per_table必须启用,innodb_file_format必须设置为Barracuda。innodb_file_per_table和innodb_file_format配置选项不适用于一般表空间。一般表空间支持所有的行格式,但需要注意的是,由于物理页大小不同,压缩表和未压缩表不能在同一通用表空间
中共存。

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

mysql>  show variables like 'innodb_file_format';
+--------------------+-----------+
| Variable_name      | Value     |
+--------------------+-----------+
| innodb_file_format | Barracuda |
+--------------------+-----------+
1 row in set (0.01 sec)

DYNAMIC表可以存储在file-per-table表空间、通用表空间和系统表空间中。要在系统表空间中存储DYNAMIC表,必须使用CREATE TABLE或ALTER TABLE语句并使用选项tablespace [=] innodb_system。innodb_file_per_table和innodb_file_format配置选项不适用于一般表空间,也不适用于使用TABLESPACE [=] innodb_system表选项在system表空间中存储DYNAMIC表。

可以通过禁用innodb_file_per_table并使用常规的CREATE TABLE或ALTER TABLE语句向系统表空间添加一个DYNAMIC表。innodb_file_format设置将被忽略。DYNAMIC表总是使用Barracuda文件格式。

DYNAMIC和COMPRESSED行格式是COMPACT行格式的变体,因此处理CHAR存储的方式与COMPACT行格式相同。

COMPACT and REDUNDANT行格式
早期版本的InnoDB使用一种未命名的文件格式(现在称为Antelope)来处理数据库文件。对于这种文件格式,表定义为ROW_FORMAT=COMPACT或ROW_FORMAT=REDUNDANT。使用这些行格式,InnoDB将可变长度列(VARCHAR, VARBINARY, BLOB和TEXT类型)的前768字节存储在b树节点的索引记录中,其余的存储在溢出页上。InnoDB还将长度大于或等于768字节的固定长度字段编码为可变长度字段,可以存储在页外。例如,如果字符集的最大字节长度大于3,那么CHAR(255)列可以超过768字节,就像utf8mb4一样。

对于Antelope文件格式,如果列的值为768字节或更少,则不需要溢出页,并且可能会节省一些I/O,因为该值位于b树节点中。这对于相对较短的blob很有效,但可能导致B树节点填充数据而不是键值,从而降低了它们的效率。具有许多BLOB列的表可能会导致B树节点的数据太满,而包含的行太少,从而使整个索引的效率低于行更短或列值存储在页外的情况。

MySQL InnoDB文件格式管理

InnoDB文件格式管理
随着InnoDB的发展,数据文件格式有时需要与以前版本的InnoDB不兼容,以支持新特性。为了在升级和降级的情况下管理兼容性,以及运行不同版本MySQL的系统,InnoDB使用命名文件格式。InnoDB目前支持两种命名文件格式,Antelope和Barracuda。

.Antelope是原始的InnoDB文件格式,以前没有一个名字。它支持紧凑和冗余的InnoDB表行格式。

.Barracuda是最新的文件格式。它支持所有InnoDB行格式,包括较新的compressed和dynamic行格式。与compressed和dynamic行格式相关的特性包括压缩表、页外列的高效存储以及高达3072字节的索引键前缀(innodb_large_prefix)。

这将讨论为新的InnoDB表启用InnoDB文件格式,验证MySQL版本之间不同文件格式的兼容性,以及识别正在使用的文件格式。

InnoDB文件格式设置不适用于存储在一般表空间中的表。通用表空间提供对所有行格式和相关特性的支持。

以下文件格式配置参数有新的默认值:
.innodb_file_format默认值修改为Barracuda。之前的默认值是Antelope。

.innodb_large_prefix默认值修改为ON。之前的默认值是OFF。

以下文件格式配置参数已弃用,并可能在将来的版本中删除:
.innodb_file_format

.innodb_file_format_check

.innodb_file_format_max

.innodb_large_prefix

文件格式配置参数用于创建与MySQL 5.1中早期版本的InnoDB兼容的表。现在MySQL 5.1已经结束了它的产品生命周期,不再需要这些参数。

启用文件格式
innodb_file_format配置选项为file-per-table表空间启用一个InnoDB文件格式。

Barracuda是默认的innodb_file_format设置。在早期版本中,默认的文件格式是Antelope。

innodb_file_format配置选项已弃用,可能在将来的版本中被删除。

当你启动mysqld时,你可以在命令行中设置innodb_file_format的值,或者在选项文件中(Unix上是my.cnf, Windows上是my.ini)。你也可以使用SET GLOBAL语句动态地修改它。

SET GLOBAL innodb_file_format=Barracuda;

使用说明
.InnoDB文件格式设置不适用于存储在一般表空间中的表。通用表空间提供对所有行格式和相关特性的支持。

.当使用CREATE table或ALTER table的TABLESPACE [=] innodb_system 表选项在system表空间中存储动态表时,innodb_file_format设置不适用。

.在创建使用动态行格式的表时,innodb_file_format设置会被忽略。

验证文件格式兼容性
InnoDB包含了一些检查来防止可能发生的崩溃和数据损坏,如果你对运行在旧版本的MySQL服务器上的InnoDB数据文件使用新文件格式可能会发生。这些检查发生在服务器启动时,以及用户第一次访问表时。本节描述这些检查,如何控制它们,以及可能出现的错误和警告条件。

向后兼容性
你只需要在使用最新版本的InnoDB (InnoDB的MySQL 5.5或更高版本)和旧版本(MySQL 5.1或更早版本,内置InnoDB而不是InnoDB插件)时考虑向后的文件格式兼容性。为了尽量减少兼容性问题,你可以在所有MySQL 5.1和更早版本的数据库服务器上使用InnoDB插件进行标准化。

一般来说,新版本的InnoDB创建的表或索引在旧版本的InnoDB中无法安全地读取或写入,而不会有崩溃、挂起、错误结果或损坏的风险。InnoDB提供了一种机制来防范这些情况,并有助于保持数据库文件和InnoDB版本之间的兼容性。这种机制可以让你利用InnoDB版本的一些新特性(如性能改进和bug修复),同时通过防止意外使用创建向下不兼容的磁盘文件的新特性,仍然保留使用旧版本InnoDB数据库的选择。

如果某个版本的InnoDB支持一种特定的文件格式(不管这种格式是否是默认的),你就可以查询和更新任何需要这种格式或更早的格式的表。根据所启用的特定文件格式,只有使用新特性创建新表的操作受到限制。相反,如果表空间包含一个使用不支持的文件格式的表或索引,则根本无法访问它,即使是读访问。

将InnoDB表空间“降级”为早期的Antelope文件格式的唯一方法是将数据复制到使用早期格式的新表中。

确定一个已经存在的InnoDB表空间的文件格式最简单的方法是检查它所包含的表的属性,使用SHOW table STATUS命令或者查询表INFORMATION_SCHEMA.TABLES。如果表的Row_format被报告为’Compressed’或’Dynamic’,则包含该表的表空间支持Barracuda格式。

内部细节
每个InnoDB file-per-table表空间(由一个*.ibd文件)文件标记了文件格式标识符。system表空间(由ibdata文件表示)被标记为在一组InnoDB数据库文件中使用的“最高”文件格式,并且当文件被打开时检查这个标记。

创建一个压缩表,或者一个带有ROW_FORMAT=DYNAMIC的表,更新对应file-per-table .ibd文件的文件头和InnoDB数据字典中的表类型,其中包含Barracuda文件格式的标识符。从那以后,这个表就不能在不支持Barracuda文件格式的InnoDB版本中使用了。为了防止异常行为,InnoDB会在打开表时进行兼容性检查。(在很多情况下,ALTER TABLE语句会重新创建一个表,从而改变它的属性。)

一般的表空间,也用*.ibd文件表示,支持Antelope和Barracuda文件格式。

ib文件集的定义
为了避免混淆,为了讨论的目的,我们将术语“ib文件集”定义为InnoDB作为一个单元管理的操作系统文件集。ib文件集合包括以下文件:

.系统表空间(一个或多个ibdata文件),包含内部系统信息(包括内部目录和undo信息),可能包括用户数据和索引。

.零个或多个单表表空间(也称为“file per table”文件,命名为*.ibd文件)。

.InnoDB日志文件;通常有两个,ib_logfile0和ib_logfile1。用于崩溃恢复和备份。

“ib文件集”不包含包含InnoDB表元数据的对应的.frm文件。.frm文件由MySQL创建和管理,有时会与InnoDB中的内部元数据不同步。

多个表(甚至来自多个数据库)可以存储在一个“ib文件集”中。(在MySQL中,“数据库”是表的逻辑集合,其他系统称之为“模式”或“目录”。)

InnoDB启动时的兼容性检查
当InnoDB打开ib文件集时,为了防止可能的崩溃或数据损坏,它会检查是否完全支持ib文件集中正在使用的文件格式。如果系统在崩溃后重新启动,或者“快速关机”(即innodb_fast_shutdown大于零),磁盘上的数据结构(如redo或undo条目,或doublewrite页面)可能对当前软件来说是“太新的”格式。在恢复过程中,如果访问了这些数据结构,可能会对数据文件造成严重的破坏。文件格式的启动检查在任何恢复过程开始之前进行,从而防止新表的一致性问题或MySQL服务器的启动问题。

从版本InnoDB 1.0.1开始,system表空间记录了ib文件集中任何表空间中任何表使用的“最高”文件格式的标识符或标记。这个文件格式标签的检查由配置参数innodb_file_format_check控制,默认是开启的。

如果system表空间中的文件格式标签比当前执行的软件支持的最高版本更新或更高,并且innodb_file_format_check开启,则在服务器启动时会发出以下错误:

InnoDB: Error: the system tablespace is in a
file format that this version doesn't support

mysql> show variables like 'innodb_file_format_check';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| innodb_file_format_check | ON    |
+--------------------------+-------+
1 row in set (0.01 sec)

mysql> show variables like 'innodb_file_format';
+--------------------+-----------+
| Variable_name      | Value     |
+--------------------+-----------+
| innodb_file_format | Barracuda |
+--------------------+-----------+
1 row in set (0.02 sec)

也可以设置“innodb_file_format”为文件格式名称。如果当前软件不支持指定的文件格式,这样做可以防止InnoDB启动。它还将“高水位标记”设置为指定的值。如果你手动“降级”ib文件集中的所有表,那么设置innodb_file_format_check的能力(在未来的版本中)是很有用的。如果你随后使用旧版本的InnoDB来访问ib文件集,那么你可以依赖启动时的文件格式检查。

在某些有限的情况下,您可能希望启动服务器并使用ib文件集,该文件集是您正在使用的软件不支持的新文件格式。如果你把配置参数innodb_file_format_check设置为OFF, InnoDB会打开数据库,但会在错误日志中显示如下警告信息:

InnoDB: Warning: the system tablespace is in a
file format that this version doesn't support

这是一个危险的设置,因为它允许恢复过程运行,如果之前的关闭是崩溃或“快速关闭”,可能会破坏数据库。

只有当你确定上一次关闭innodb_fast_shutdown=0时,才应该将innodb_file_format_check设置为OFF,这样基本上没有恢复过程发生。

参数innodb_file_format_check只影响打开数据库时发生的操作,不会影响后续操作。相反,参数innodb_file_format(启用特定的格式)只确定是否可以以启用的格式创建新表,对数据库是否可以打开没有影响。

文件格式标记是一个“高水位标记”,如果创建了一个“更高”格式的表,或者访问一个现有的表进行读或写(假设支持它的格式),那么在服务器启动后,它就会增加。如果你以高于运行软件支持的格式访问一个已经存在的表,系统表空间标签不会更新,但是表级别的兼容性检查会应用(并且会发出错误),如14.10.2.2节“打开表时兼容性检查”所述。每当高水位线更新时,innodb_file_format_check的值也会更新,因此执行SELECT @@innodb_file_format_check;显示当前打开的ib文件集中的表使用的、当前执行软件支持的最新文件格式的名称。

mysql> SELECT @@innodb_file_format_check;
+----------------------------+
| @@innodb_file_format_check |
+----------------------------+
|                          1 |
+----------------------------+
1 row in set (0.00 sec)

打开表时检查兼容性
当第一次访问表时,InnoDB(包括一些InnoDB 1.0之前的版本)会检查存储表的表空间的文件格式是否完全支持。这种检查可以防止使用“太新”数据结构的表出现崩溃或损坏。

使用某个版本支持的任何文件格式的所有表都可以读或写(假设用户有足够的权限)。设置系统配置参数innodb_file_format可以防止创建使用特定文件格式的新表,即使给定的版本支持这种文件格式。这样的设置可以用来保持向后兼容性,但它不会阻止访问任何使用支持的格式的表。

如果在创建表时使用了新的文件格式,那么5.0.21之前的MySQL版本不能可靠地使用新版本创建的数据库文件。为了防止各种错误或损坏,InnoDB在打开文件时(例如,第一次访问一张表时)会检查文件格式的兼容性。如果当前运行的InnoDB版本不支持InnoDB数据字典中表类型标识的文件格式,MySQL报告如下错误:

ERROR 1146 (42S02): Table 'test.t1' doesn't exist

InnoDB也会在错误日志中写入一条消息:

InnoDB: table test/t1: unknown table type 33

MySQL 4.1之前的InnoDB版本在数据库文件中不包含表格式标识符,MySQL 5.0.21之前的版本不包含表格式兼容性检查。因此,如果在5.0.21之前的InnoDB版本中使用了较新的文件格式的表,则无法确保操作是正确的。

InnoDB 1.0及更高版本的文件格式管理能力(表空间标记和运行时检查)允许InnoDB尽快验证运行版本的软件能够正确处理数据库中存在的表。

如果你允许InnoDB打开一个包含它不支持的文件格式的数据库(通过设置参数innodb_file_format_check为OFF),本节描述的表级检查仍然适用。

在使用InnoDB插件的MySQL 5.1之前的版本中强烈建议用户不要使用包含Barracuda文件格式表的数据库文件。可以使用Antelope格式重建这样的表。

识别正在使用的文件格式
如果您使用innodb_file_format配置选项启用不同的文件格式,则更改仅适用于新创建的表。此外,当您创建一个新表时,包含该表的表空间被标记为支持表特性所需的“最早”或“最简单”文件格式。例如,如果您启用了Barracuda文件格式,并创建了一个不使用Dynamic或Compressed行格式的新表,那么包含该表的新表空间将被标记为使用Antelope文件格式。

很容易识别给定表使用的文件格式。如果SHOW TABLE STATUS报告的行格式是Compact或Redundant,则表使用Antelope文件格式。如果SHOW TABLE STATUS报告的行格式是Compressed或Dynamic,则表使用Barracuda文件格式。


mysql> SHOW TABLE STATUS\G
*************************** 1. row ***************************
           Name: big_table
         Engine: InnoDB
        Version: 10
     Row_format: Dynamic
           Rows: 3370592
 Avg_row_length: 205
    Data_length: 694140928
Max_data_length: 0
   Index_length: 0
      Data_free: 3145728
 Auto_increment: 3326977
    Create_time: 2023-07-06 18:05:18
    Update_time: NULL
     Check_time: NULL
      Collation: utf8mb4_general_ci
       Checksum: NULL
 Create_options:
        Comment:

您还可以使用InnoDB INFORMATION_SCHEMA表识别给定表或表空间使用的文件格式。例如:

mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME='undo/big_table'\G
*************************** 1. row ***************************
     TABLE_ID: 488
         NAME: undo/big_table
         FLAG: 33
       N_COLS: 25
        SPACE: 487
  FILE_FORMAT: Barracuda
   ROW_FORMAT: Dynamic
ZIP_PAGE_SIZE: 0
   SPACE_TYPE: Single
1 row in set (0.00 sec)


mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES WHERE NAME='undo/big_table'\G
*************************** 1. row ***************************
         SPACE: 487
          NAME: undo/big_table
          FLAG: 33
   FILE_FORMAT: Barracuda
    ROW_FORMAT: Dynamic
     PAGE_SIZE: 16384
 ZIP_PAGE_SIZE: 0
    SPACE_TYPE: Single
 FS_BLOCK_SIZE: 4096
     FILE_SIZE: 708837376
ALLOCATED_SIZE: 708841472
1 row in set (0.00 sec)

修改文件格式
每个InnoDB表空间文件(名称匹配*.ibd)都被标记为用于创建其表和索引的文件格式。修改文件格式的方法是重新创建表及其索引。重建表及其索引的最简单方法是在每个想要修改的表上使用以下命令:

ALTER TABLE t ROW_FORMAT=format_name;

如果您正在修改文件格式以降级到较旧的MySQL版本,则可能存在表存储格式的不兼容性,需要额外的步骤。

MySQL InnoDB页面压缩

InnoDB页面压缩
innoDB支持页面级别的表压缩,这些表位于file-per-table表空间中。这个特性被称为透明页面压缩。通过使用CREATE TABLE或ALTER TABLE指定compression属性,可以启用页面压缩。支持的压缩算法包括Zlib和LZ4。

支持平台
页面压缩需要稀疏文件和穿孔支持。在带有NTFS的Windows上,以及以下支持mysql的Linux平台子集上支持页面压缩,其中内核级别提供了hole punch支持:
. RHEL 7 and derived distributions that use kernel version 3.10.0-123 or higher
. OEL 5.10 (UEK2) kernel version 2.6.39 or higher
. OEL 6.5 (UEK3) kernel version 3.8.13 or higher
. OEL 7.0 kernel version 3.8.13 or higher
. SLE11 kernel version 3.0-x
. SLE12 kernel version 3.12-x
. OES11 kernel version 3.0-x
. Ubuntu 14.0.4 LTS kernel version 3.13 or higher
. Ubuntu 12.0.4 LTS kernel version 3.2 or higher
. Debian 7 kernel version 3.2 or higher

对于给定的Linux发行版,所有可用的文件系统可能都不支持打孔。

页面压缩工作原理
在写入一页时,使用指定的压缩算法对其进行压缩。压缩后的数据被写入磁盘,在磁盘上打孔机制从页的末尾释放空块。如果压缩失败,数据会原样写入。

Linux上的打孔尺寸
在Linux系统中,文件系统块长度是用于打孔的单位长度。因此,只有当页面数据可以压缩到小于或等于InnoDB页面大小减去文件系统块大小时,页面压缩才有效。例如,如果innodb_page_size=16K,文件系统块大小为4K,则页面数据必须压缩到小于或等于12K,才能穿孔。

Windows上的打孔尺寸
在Windows系统上,用于稀疏文件的底层基础设施是基于NTFS压缩。冲孔尺寸为NTFS压缩单元,是NTFS集群尺寸的16倍。集群大小及其压缩单位如下表所示:

Windows NTFS集群大小和压缩单元
集群大小 压缩单元
512 Bytes 8 KB
1 KB 16 KB
2 KB 32 KB
4 KB 64 KB

在Windows系统上,只有当页面数据可以压缩到小于或等于InnoDB页面大小减去压缩单位大小时,页面压缩才有效。

NTFS集群的默认大小是4K,其中压缩单位大小是64K。这意味着页面压缩对于开箱即用的Windows NTFS配置没有任何好处,因为innodb_page_size的最大值也是64K。

为了让页面压缩在Windows上工作,创建文件系统时必须使用小于4K的集群大小,并且innodb_page_size必须至少是压缩单元大小的两倍。例如,为了让页面压缩在Windows上工作,你可以构建一个512字节的集群文件系统(压缩单位是8KB),并将InnoDB初始化为16K或更高的值。

启用页面压缩
要启用页面压缩,请在CREATE TABLE语句中指定compression属性。例如:

mysql> CREATE TABLE t7 (c1 INT) COMPRESSION="zlib";
Query OK, 0 rows affected (0.03 sec)

您还可以在ALTER TABLE语句中启用页面压缩。但是,ALTER TABLE…COMPRESSION只更新表空间的COMPRESSION属性。在设置新的压缩算法之后,对表空间的写入将使用新的设置,但是要将新的压缩算法应用到现有页面,必须使用OPTIMIZE table重建表。
mysql>  CREATE TABLE t8 (c1 INT);
Query OK, 0 rows affected (0.01 sec)

mysql>  ALTER TABLE t8 COMPRESSION="zlib";
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> OPTIMIZE TABLE t8;
+---------+----------+----------+-------------------------------------------------------------------+
| Table   | Op       | Msg_type | Msg_text                                                          |
+---------+----------+----------+-------------------------------------------------------------------+
| undo.t8 | optimize | note     | Table does not support optimize, doing recreate + analyze instead |
| undo.t8 | optimize | status   | OK                                                                |
+---------+----------+----------+-------------------------------------------------------------------+
2 rows in set (0.02 sec)

对于Innodb存储引擎不能支持optimize table,Myisam存储引擎支持optimize table。

禁用页面压缩
要禁用页面压缩,请使用ALTER TABLE设置compression =None。在设置COMPRESSION=None后,写入表空间不再使用页面压缩。要解压缩现有页面,必须在设置COMPRESSION=None后使用OPTIMIZE TABLE重新构建表。

mysql> ALTER TABLE t8 COMPRESSION="None";
Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> OPTIMIZE TABLE t8;
+---------+----------+----------+-------------------------------------------------------------------+
| Table   | Op       | Msg_type | Msg_text                                                          |
+---------+----------+----------+-------------------------------------------------------------------+
| undo.t8 | optimize | note     | Table does not support optimize, doing recreate + analyze instead |
| undo.t8 | optimize | status   | OK                                                                |
+---------+----------+----------+-------------------------------------------------------------------+
2 rows in set (0.02 sec)

mysql> show create table t8;
+-------+------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                               |
+-------+------------------------------------------------------------------------------------------------------------+
| t8    | CREATE TABLE `t8` (
  `c1` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMPRESSION='None' |
+-------+------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

页面压缩元数据
页面压缩元数据可以在INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES表中找到。在下列列中:
.FS_BLOCK_SIZE:文件系统块大小,打孔时使用的单位大小。

.FILE_SIZE:文件的外观大小,表示未压缩时文件的最大大小。

.ALLOCATED_SIZE:文件的实际大小,即在磁盘上分配的空间量。

在类unix系统上,使用ls -l tablespace_name.ibd以字节为单位给出了明显的文件长度(相当于FILE_SIZE)。要查看磁盘上实际分配的空间大小(相当于ALLOCATED_SIZE),可以使用du –block-size=1 tablespace_name.ibd。–block-size=1选项以字节(而不是块)打印分配的空间,以便与ls -l的输出进行比较。

使用SHOW CREATE TABLE查看当前页面压缩设置(Zlib、Lz4或None)。一个表可能包含具有不同压缩设置的混合页面。

在下面的示例中,从INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES表中检索employees表的页面压缩元数据。

# Create the employees table with Zlib page compression
mysql> CREATE TABLE employees (
    -> emp_no INT NOT NULL,
    -> birth_date DATE NOT NULL,
    -> first_name VARCHAR(14) NOT NULL,
    -> last_name VARCHAR(16) NOT NULL,
    -> gender ENUM ('M','F') NOT NULL,
    -> hire_date DATE NOT NULL,
    -> PRIMARY KEY (emp_no)
    -> ) COMPRESSION="zlib";
Query OK, 0 rows affected (0.01 sec)

# Insert data
mysql> insert into employees values(1,'1985-02-28','yong','jing','M','2023-08-04');
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)


# Query page compression metadata in INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES

mysql> SELECT SPACE, NAME, FS_BLOCK_SIZE, FILE_SIZE, ALLOCATED_SIZE FROM
    -> INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES WHERE NAME='undo/employees'\G
*************************** 1. row ***************************
         SPACE: 498
          NAME: undo/employees
 FS_BLOCK_SIZE: 4096
     FILE_SIZE: 98304
ALLOCATED_SIZE: 61440
1 row in set (0.01 sec)

employees表的页面压缩元数据显示,表面文件大小为98304字节,而实际文件大小(使用页面压缩)为61440字节。文件系统块大小为4096字节,即穿孔时使用的块大小。

页面压缩限制和使用说明
.如果文件系统块大小(或Windows上的压缩单位大小)* 2>innodb_page_size禁用页面压缩。

.对于驻留在共享表空间中的表,包括system表空间、临时表空间和一般表空间,不支持页面压缩。

.undo日志表空间不支持页面压缩。

.重做日志页面不支持页面压缩。

.用于空间索引的R树页面不能被压缩。

.属于压缩表(ROW_FORMAT= compressed)的页面保持原样。

.在恢复过程中,更新后的页面将以未压缩的形式输出。

.在不支持所用压缩算法的服务器上加载页压缩表空间会导致I/O错误。

.在降级到不支持页面压缩的MySQL早期版本之前,请解压使用页面压缩特性的表。要解压一张表,运行ALTER table…compression=None和
optimize table。

.如果所使用的压缩算法在Linux和Windows服务器上可用,则可以在Linux和Windows服务器之间复制页压缩表空间。

.在将页面压缩的表空间文件从一台主机移动到另一台主机时保持页面压缩需要一个保留稀疏文件的实用程序。

.与其他平台相比,使用NVMFS的Fusion-io硬件可以实现更好的页面压缩,因为NVMFS旨在利用打孔功能。

.在InnoDB页面大小较大和文件系统块相对较小的情况下使用页面压缩特性可能会导致写入放大。例如,InnoDB页的最大大小为64KB,而文件系统块的大小为4KB,这可能会提高压缩性能,但也可能会增加对缓冲池的需求,从而导致I/O增加和潜在的写放大。