MySQL8-中文参考-三十三-

MySQL8 中文参考(三十三)

原文:docs.oracle.com/javase/tutorial/reallybigindex.html

17.15.4 InnoDB INFORMATION_SCHEMA FULLTEXT 索引表

原文:dev.mysql.com/doc/refman/8.0/en/innodb-information-schema-fulltext_index-tables.html

以下表格提供了 FULLTEXT 索引的元数据:

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                     |
+-------------------------------------------+

表格概述

  • INNODB_FT_CONFIG:提供关于 InnoDB 表的 FULLTEXT 索引和相关处理的元数据。

  • INNODB_FT_BEING_DELETED:提供 INNODB_FT_DELETED 表的快照;仅在 OPTIMIZE TABLE 维护操作期间使用。运行 OPTIMIZE TABLE 时,INNODB_FT_BEING_DELETED 表会被清空,并且从 INNODB_FT_DELETED 表中删除 DOC_ID 值。由于 INNODB_FT_BEING_DELETED 的内容通常寿命较短,因此该表对于监控或调试具有有限的实用性。有关在具有 FULLTEXT 索引的表上运行 OPTIMIZE TABLE 的信息,请参见 第 14.9.6 节,“调整 MySQL 全文搜索”。

  • INNODB_FT_DELETED:存储从 InnoDB 表的 FULLTEXT 索引中删除的行。为了避免在 InnoDB FULLTEXT 索引的 DML 操作期间进行昂贵的索引重组,新删除的单词信息被单独存储,当进行文本搜索时会从搜索结果中过滤掉,并且仅当对 InnoDB 表发出 OPTIMIZE TABLE 语句时才从主搜索索引中��除。

  • INNODB_FT_DEFAULT_STOPWORD:保存在创建 InnoDB 表的 FULLTEXT 索引时默认使用的 停用词 列表。

    有关INNODB_FT_DEFAULT_STOPWORD表的信息,请参阅 Section 14.9.4, “全文停用词”。

  • INNODB_FT_INDEX_TABLE:提供有关用于处理对InnoDB表的FULLTEXT索引进行文本搜索的倒排索引的信息。

  • INNODB_FT_INDEX_CACHE:提供有关FULLTEXT索引中新插入行的标记信息。为避免在 DML 操作期间进行昂贵的索引重组,新索引单词的信息被单独存储,并仅在运行OPTIMIZE TABLE时,服务器关闭时,或者缓存大小超过由innodb_ft_cache_sizeinnodb_ft_total_cache_size系统变量定义的限制时,才与主搜索索引合并。

注意

除了INNODB_FT_DEFAULT_STOPWORD表外,这些表最初是空的。在查询任何这些表之前,将innodb_ft_aux_table系统变量的值设置为包含FULLTEXT索引的表的名称(包括数据库名称)(例如,test/articles)。

示例 17.5 InnoDB FULLTEXT 索引 INFORMATION_SCHEMA 表

本示例使用具有FULLTEXT索引的表来演示FULLTEXT索引INFORMATION_SCHEMA表中包含的数据。

  1. 创建一个具有FULLTEXT索引的表并插入一些数据:

    mysql> CREATE TABLE articles (
             id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
             title VARCHAR(200),
             body TEXT,
             FULLTEXT (title,body)
           ) ENGINE=InnoDB;
    
    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 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 ...');
    
  2. innodb_ft_aux_table变量设置为具有FULLTEXT索引的表的名称。如果未设置此变量,则InnoDB FULLTEXT INFORMATION_SCHEMA表为空,除了INNODB_FT_DEFAULT_STOPWORD

    mysql> SET GLOBAL innodb_ft_aux_table = 'test/articles';
    
  3. 查询INNODB_FT_INDEX_CACHE表,显示FULLTEXT索引中新插入行的信息。为避免在 DML 操作期间进行昂贵的索引重组,新插入行的数据仍保留在FULLTEXT索引缓存中,直到运行OPTIMIZE TABLE(或者直到服务器关闭或超过缓存限制)。

    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 |
    +------------+--------------+-------------+-----------+--------+----------+
    
  4. 启用 innodb_optimize_fulltext_only 系统变量,并在包含 FULLTEXT 索引的表上运行 OPTIMIZE TABLE。此操作将 FULLTEXT 索引缓存的内容刷新到主 FULLTEXT 索引中。innodb_optimize_fulltext_only 改变了 OPTIMIZE TABLE 语句在 InnoDB 表上的操作方式,并且旨在在具有 FULLTEXT 索引的 InnoDB 表上的维护操作期间临时启用。

    mysql> SET GLOBAL innodb_optimize_fulltext_only=ON;
    
    mysql> OPTIMIZE TABLE articles;
    +---------------+----------+----------+----------+
    | Table         | Op       | Msg_type | Msg_text |
    +---------------+----------+----------+----------+
    | test.articles | optimize | status   | OK       |
    +---------------+----------+----------+----------+
    
  5. 查询 INNODB_FT_INDEX_TABLE 表,查看主 FULLTEXT 索引中的数据信息,包括刚刚从 FULLTEXT 索引缓存中刷新的数据信息。

    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 |
    +------------+--------------+-------------+-----------+--------+----------+
    

    INNODB_FT_INDEX_CACHE 表现在为空,因为 OPTIMIZE TABLE 操作刷新了 FULLTEXT 索引缓存。

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

    mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_DELETED;
    +--------+
    | DOC_ID |
    +--------+
    |      2 |
    |      3 |
    |      4 |
    +--------+
    
  8. 运行 OPTIMIZE TABLE 来删除已删除的记录。

    mysql> OPTIMIZE TABLE articles;
    +---------------+----------+----------+----------+
    | Table         | Op       | Msg_type | Msg_text |
    +---------------+----------+----------+----------+
    | test.articles | optimize | status   | OK       |
    +---------------+----------+----------+----------+
    

    INNODB_FT_DELETED 表现在应该为空。

    mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_DELETED;
    Empty set (0.00 sec)
    
  9. 查询 INNODB_FT_CONFIG 表。该表包含关于 FULLTEXT 索引和相关处理的元数据:

    • optimize_checkpoint_limit: 多少秒后运行 OPTIMIZE TABLE 停止。

    • synced_doc_id: 下一个要发行的 DOC_ID

    • stopword_table_name: 用户定义的停用词表的 database/table 名称。如果没有用户定义的停用词表,则 VALUE 列为空。

    • use_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     |
    +---------------------------+-------+
    
  10. 禁用innodb_optimize_fulltext_only,因为它只打算暂时启用:

    mysql> SET GLOBAL innodb_optimize_fulltext_only=OFF;
    

17.15.5 InnoDB INFORMATION_SCHEMA 缓冲池表

原文:dev.mysql.com/doc/refman/8.0/en/innodb-information-schema-buffer-pool-tables.html

InnoDB INFORMATION_SCHEMA缓冲池表提供有关InnoDB缓冲池内页面的缓冲池状态信息和元数据。

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                      |
+-----------------------------------------------+

表概述

  • 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_PAGEINNODB_BUFFER_PAGE_LRU表可能会影响性能。除非您意识到性能影响并确定其可接受,否则不要在生产系统上查询这些表。为避免影响生产系统的性能,请在测试实例上重现您想要调查的问题,并查询缓冲池统计信息。

示例 17.6 在 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(*) |
+----------+
|     1516 |
+----------+

此查询返回包含系统数据的页面的大致数量,缓冲池页面的总��,以及包含系统数据的页面的大致百分比。

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 |
+--------------+-------------+------------------------+
|          295 |        8192 |                      4 |
+--------------+-------------+------------------------+

通过查询 PAGE_TYPE 值可以确定缓冲池中的系统数据类型。例如,以下查询返回包含系统数据的页面中的八个不同的 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            |
| IBUF_BITMAP       |
| UNKNOWN           |
| FILE_SPACE_HEADER |
| INODE             |
| UNDO_LOG          |
| ALLOCATED         |
+-------------------+

示例 17.7 在 INNODB_BUFFER_PAGE 表中查询用户数据

此查询通过计算 TABLE_NAME 值为 NOT NULLNOT LIKE '%INNODB_TABLES%' 的页面数量,提供包含用户数据的页面的大致计数。

mysql> SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE
       WHERE TABLE_NAME IS NOT NULL AND TABLE_NAME NOT LIKE '%INNODB_TABLES%';
+----------+
| COUNT(*) |
+----------+
|     7897 |
+----------+

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

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 |
+------------+-------------+----------------------+
|       7897 |        8192 |                   96 |
+------------+-------------+----------------------+

此查询标识具有缓冲池中页面的用户定义表:

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              |
+-------------------------+
| `employees`.`salaries`  |
| `employees`.`employees` |
+-------------------------+

示例 17.8 在 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     |  1609 |              25 |
+------------+-------+-----------------+

此查询返回了在 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     |  1608 |              25 |
| PRIMARY    |  6086 |              95 |
+------------+-------+-----------------+

示例 17.9 在 INNODB_BUFFER_PAGE_LRU 表中查询 LRU_POSITION 数据

INNODB_BUFFER_PAGE_LRU 表包含关于 InnoDB 缓冲池中页面的信息,特别是它们的排序方式,确定了在缓冲池变满时应该驱逐哪些页面。该页面的定义与 INNODB_BUFFER_PAGE 相同,只是该表具有一个 LRU_POSITION 列而不是一个 BLOCK_ID 列。

此查询计算了 employees.employees 表页面在 LRU 列中特定位置上所占的位置数。

mysql> SELECT COUNT(LRU_POSITION) FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE_LRU
       WHERE TABLE_NAME='`employees`.`employees`' AND LRU_POSITION < 3072;
+---------------------+
| COUNT(LRU_POSITION) |
+---------------------+
|                 548 |
+---------------------+

示例 17.10 查询 INNODB_BUFFER_POOL_STATS 表

INNODB_BUFFER_POOL_STATS 表提供类似于 SHOW ENGINE INNODB STATUSInnoDB 缓冲池状态变量的信息。

mysql> SELECT * FROM information_schema.INNODB_BUFFER_POOL_STATS \G
*************************** 1\. row ***************************
                         POOL_ID: 0
                       POOL_SIZE: 8192
                    FREE_BUFFERS: 1
                  DATABASE_PAGES: 8173
              OLD_DATABASE_PAGES: 3014
         MODIFIED_DATABASE_PAGES: 0
              PENDING_DECOMPRESS: 0
                   PENDING_READS: 0
               PENDING_FLUSH_LRU: 0
              PENDING_FLUSH_LIST: 0
                PAGES_MADE_YOUNG: 15907
            PAGES_NOT_MADE_YOUNG: 3803101
           PAGES_MADE_YOUNG_RATE: 0
       PAGES_MADE_NOT_YOUNG_RATE: 0
               NUMBER_PAGES_READ: 3270
            NUMBER_PAGES_CREATED: 13176
            NUMBER_PAGES_WRITTEN: 15109
                 PAGES_READ_RATE: 0
               PAGES_CREATE_RATE: 0
              PAGES_WRITTEN_RATE: 0
                NUMBER_PAGES_GET: 33069332
                        HIT_RATE: 0
    YOUNG_MAKE_PER_THOUSAND_GETS: 0
NOT_YOUNG_MAKE_PER_THOUSAND_GETS: 0
         NUMBER_PAGES_READ_AHEAD: 2713
       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

为了比较起见,以下是基于相同数据集的 SHOW ENGINE INNODB STATUS 输出和 InnoDB 缓冲池状态变量输出。

要了解有关 SHOW ENGINE INNODB STATUS 输出的更多信息,请参阅 第 17.17.3 节,“InnoDB 标准监视器和锁监视器输出”。

mysql> SHOW ENGINE INNODB STATUS \G
...
----------------------
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 137428992
Dictionary memory allocated 579084
Buffer pool size   8192
Free buffers       1
Database pages     8173
Old database pages 3014
Modified db pages  0
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 15907, not young 3803101
0.00 youngs/s, 0.00 non-youngs/s
Pages read 3270, created 13176, written 15109
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: 8173, unzip_LRU len: 0
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
...

对于状态变量的描述,请参见第 7.1.10 节,“服务器状态变量”。

mysql> SHOW STATUS LIKE 'Innodb_buffer%';
+---------------------------------------+-------------+
| Variable_name                         | Value       |
+---------------------------------------+-------------+
| Innodb_buffer_pool_dump_status        | not started |
| Innodb_buffer_pool_load_status        | not started |
| Innodb_buffer_pool_resize_status      | not started |
| Innodb_buffer_pool_pages_data         | 8173        |
| Innodb_buffer_pool_bytes_data         | 133906432   |
| Innodb_buffer_pool_pages_dirty        | 0           |
| Innodb_buffer_pool_bytes_dirty        | 0           |
| Innodb_buffer_pool_pages_flushed      | 15109       |
| Innodb_buffer_pool_pages_free         | 1           |
| Innodb_buffer_pool_pages_misc         | 18          |
| Innodb_buffer_pool_pages_total        | 8192        |
| Innodb_buffer_pool_read_ahead_rnd     | 0           |
| Innodb_buffer_pool_read_ahead         | 2713        |
| Innodb_buffer_pool_read_ahead_evicted | 0           |
| Innodb_buffer_pool_read_requests      | 33069332    |
| Innodb_buffer_pool_reads              | 558         |
| Innodb_buffer_pool_wait_free          | 0           |
| Innodb_buffer_pool_write_requests     | 11985961    |
+---------------------------------------+-------------+

17.15.6 InnoDB INFORMATION_SCHEMA Metrics 表

原文:dev.mysql.com/doc/refman/8.0/en/innodb-information-schema-metrics-table.html

INNODB_METRICS 表提供关于 InnoDB 性能和资源相关计数器的信息。

INNODB_METRICS 表列如下。有关列描述,请参见 Section 28.4.21, “INFORMATION_SCHEMA INNODB_METRICS 表”。

mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME="dml_inserts" \G
*************************** 1\. row ***************************
           NAME: dml_inserts
      SUBSYSTEM: dml
          COUNT: 46273
      MAX_COUNT: 46273
      MIN_COUNT: NULL
      AVG_COUNT: 492.2659574468085
    COUNT_RESET: 46273
MAX_COUNT_RESET: 46273
MIN_COUNT_RESET: NULL
AVG_COUNT_RESET: NULL
   TIME_ENABLED: 2014-11-28 16:07:53
  TIME_DISABLED: NULL
   TIME_ELAPSED: 94
     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_openedmetadata_table_handles_closed 计数器,在 MySQL 服务器配置文件的 [mysqld] 部分中输入以下行。

[mysqld]
innodb_monitor_enable = log,metadata_table_handles_opened,metadata_table_handles_closed

在配置文件中启用多个计数器或模块时,请指定 innodb_monitor_enable 变量,后跟以逗号分隔的计数器和模块名称,如上所示。只能在配置文件中使用 innodb_monitor_enable 变量。innodb_monitor_disableinnodb_monitor_reset 变量仅在命令行上受支持。

注意

由于每个计数器都会增加运行时开销,建议在生产服务器上谨慎使用计数器来诊断特定问题或监视特定功能。建议在测试或开发服务器上更广泛地使用计数器。

计数器

可用计数器列表可能会更改。查询信息模式 INNODB_METRICS 表,以获��您的 MySQL 服务器版本中可用的计数器。

默认启用的计数器对应于 SHOW ENGINE INNODB STATUS 输出中显示的计数器。在 SHOW ENGINE INNODB STATUS 输出中显示的计数器始终在系统级别启用,但可以在 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_neighbor                       | buffer              | disabled |
| buffer_flush_neighbor_pages                 | buffer              | disabled |
| buffer_flush_neighbor_total_pages           | buffer              | disabled |
| buffer_flush_n_to_flush_by_age              | buffer              | disabled |
| buffer_flush_n_to_flush_by_dirty_page       | 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_rseg_array                 | 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_on_log_no_waits         | buffer_page_io      | disabled |
| buffer_page_written_on_log_waits            | buffer_page_io      | disabled |
| buffer_page_written_on_log_wait_loops       | buffer_page_io      | disabled |
| buffer_page_written_other                   | buffer_page_io      | disabled |
| buffer_page_written_rseg_array              | 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 |
| cpu_n                                       | cpu                 | disabled |
| cpu_stime_abs                               | cpu                 | disabled |
| cpu_stime_pct                               | cpu                 | disabled |
| cpu_utime_abs                               | cpu                 | disabled |
| cpu_utime_pct                               | cpu                 | disabled |
| dblwr_async_requests                        | dblwr               | disabled |
| dblwr_flush_requests                        | dblwr               | disabled |
| dblwr_flush_wait_events                     | dblwr               | disabled |
| dblwr_sync_requests                         | dblwr               | 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_system_deletes                          | dml                 | enabled  |
| dml_system_inserts                          | dml                 | enabled  |
| dml_system_reads                            | dml                 | enabled  |
| dml_system_updates                          | dml                 | enabled  |
| 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_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_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_deadlock_false_positives               | lock                | enabled  |
| lock_deadlock_rounds                        | lock                | enabled  |
| lock_rec_grant_attempts                     | 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_rec_release_attempts                   | lock                | enabled  |
| 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_schedule_refreshes                     | 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_threads_waiting                        | lock                | enabled  |
| lock_timeouts                               | lock                | enabled  |
| log_checkpoints                             | log                 | disabled |
| log_concurrency_margin                      | log                 | disabled |
| log_flusher_no_waits                        | log                 | disabled |
| log_flusher_waits                           | log                 | disabled |
| log_flusher_wait_loops                      | log                 | disabled |
| log_flush_avg_time                          | log                 | disabled |
| log_flush_lsn_avg_rate                      | log                 | disabled |
| log_flush_max_time                          | log                 | disabled |
| log_flush_notifier_no_waits                 | log                 | disabled |
| log_flush_notifier_waits                    | log                 | disabled |
| log_flush_notifier_wait_loops               | log                 | disabled |
| log_flush_total_time                        | log                 | disabled |
| log_free_space                              | log                 | disabled |
| log_full_block_writes                       | log                 | disabled |
| log_lsn_archived                            | log                 | disabled |
| log_lsn_buf_dirty_pages_added               | log                 | disabled |
| log_lsn_buf_pool_oldest_approx              | log                 | disabled |
| log_lsn_buf_pool_oldest_lwm                 | log                 | disabled |
| log_lsn_checkpoint_age                      | log                 | disabled |
| log_lsn_current                             | log                 | disabled |
| log_lsn_last_checkpoint                     | log                 | disabled |
| log_lsn_last_flush                          | log                 | disabled |
| log_max_modified_age_async                  | log                 | disabled |
| log_max_modified_age_sync                   | log                 | disabled |
| log_next_file                               | log                 | disabled |
| log_on_buffer_space_no_waits                | log                 | disabled |
| log_on_buffer_space_waits                   | log                 | disabled |
| log_on_buffer_space_wait_loops              | log                 | disabled |
| log_on_file_space_no_waits                  | log                 | disabled |
| log_on_file_space_waits                     | log                 | disabled |
| log_on_file_space_wait_loops                | log                 | disabled |
| log_on_flush_no_waits                       | log                 | disabled |
| log_on_flush_waits                          | log                 | disabled |
| log_on_flush_wait_loops                     | log                 | disabled |
| log_on_recent_closed_wait_loops             | log                 | disabled |
| log_on_recent_written_wait_loops            | log                 | disabled |
| log_on_write_no_waits                       | log                 | disabled |
| log_on_write_waits                          | log                 | disabled |
| log_on_write_wait_loops                     | log                 | disabled |
| log_padded                                  | log                 | disabled |
| log_partial_block_writes                    | log                 | disabled |
| log_waits                                   | log                 | enabled  |
| log_writer_no_waits                         | log                 | disabled |
| log_writer_on_archiver_waits                | log                 | disabled |
| log_writer_on_file_space_waits              | log                 | disabled |
| log_writer_waits                            | log                 | disabled |
| log_writer_wait_loops                       | log                 | disabled |
| log_writes                                  | log                 | enabled  |
| log_write_notifier_no_waits                 | log                 | disabled |
| log_write_notifier_waits                    | log                 | disabled |
| log_write_notifier_wait_loops               | log                 | disabled |
| log_write_requests                          | log                 | enabled  |
| log_write_to_file_requests_interval         | log                 | disabled |
| metadata_table_handles_closed               | metadata            | disabled |
| metadata_table_handles_opened               | metadata            | disabled |
| metadata_table_reference_count              | metadata            | disabled |
| module_cpu                                  | cpu                 | disabled |
| module_dblwr                                | dblwr               | disabled |
| module_page_track                           | page_track          | 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 |
| page_track_checkpoint_partial_flush_request | page_track          | disabled |
| page_track_full_block_writes                | page_track          | disabled |
| page_track_partial_block_writes             | page_track          | disabled |
| page_track_resets                           | page_track          | 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_truncate_history_count                | purge               | disabled |
| purge_truncate_history_usec                 | purge               | disabled |
| purge_undo_log_pages                        | purge               | disabled |
| purge_upd_exist_or_extern_records           | purge               | disabled |
| sampled_pages_read                          | sampling            | disabled |
| sampled_pages_skipped                       | sampling            | disabled |
| trx_active_transactions                     | transaction         | disabled |
| trx_allocations                             | transaction         | disabled |
| trx_commits_insert_update                   | transaction         | disabled |
| trx_nl_ro_commits                           | transaction         | disabled |
| trx_on_log_no_waits                         | transaction         | disabled |
| trx_on_log_waits                            | transaction         | disabled |
| trx_on_log_wait_loops                       | 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 |
| undo_truncate_count                         | undo                | disabled |
| undo_truncate_done_logging_count            | undo                | disabled |
| undo_truncate_start_logging_count           | undo                | disabled |
| undo_truncate_usec                          | undo                | disabled |
+---------------------------------------------+---------------------+----------+
314 rows in set (0.00 sec)

计数器模块

每个计数器与特定模块相关联。模块名称可用于启用、禁用或重置特定子系统的所有计数器。例如,使用 module_dml 可以启��与 dml 子系统相关的所有计数器。

mysql> SET GLOBAL innodb_monitor_enable = module_dml;

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 |
+-------------+-----------+---------+

模块名称可与 innodb_monitor_enable 和相关变量一起使用。

模块名称及其对应的 SUBSYSTEM 名称如下。

  • 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 = log)

  • module_metadata (subsystem = metadata)

  • module_os (subsystem = os)

  • module_purge (subsystem = purge)

  • module_trx (subsystem = transaction)

  • module_undo (subsystem = undo)

示例 17.11 使用 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.02 sec)
    
  2. 启用 dml_inserts 计数器。

    mysql> SET GLOBAL innodb_monitor_enable = dml_inserts;
    Query OK, 0 rows affected (0.01 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 |
    +-------------+-------------------------+
    
  3. 查询 dml_inserts 计数器数据的 INNODB_METRICS 表。因为没有执行 DML 操作,计数器值为零或 NULL。TIME_ENABLEDTIME_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: 2014-12-04 14:18:28
      TIME_DISABLED: NULL
       TIME_ELAPSED: 28
         TIME_RESET: NULL
             STATUS: enabled
               TYPE: status_counter
            COMMENT: Number of rows inserted
    
  4. 向表中插入三行数据。

    mysql> INSERT INTO t1 values(1);
    Query OK, 1 row affected (0.00 sec)
    
    mysql> INSERT INTO t1 values(2);
    Query OK, 1 row affected (0.00 sec)
    
    mysql> INSERT INTO t1 values(3);
    Query OK, 1 row affected (0.00 sec)
    
  5. 再次查询INNODB_METRICS表以获取dml_inserts计数器数据。现在已经增加了许多计数器值,包括COUNTMAX_COUNTAVG_COUNTCOUNT_RESET。请参考INNODB_METRICS表定义,了解这些值的描述。

    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.046153846153846156
        COUNT_RESET: 3
    MAX_COUNT_RESET: 3
    MIN_COUNT_RESET: NULL
    AVG_COUNT_RESET: NULL
       TIME_ENABLED: 2014-12-04 14:18:28
      TIME_DISABLED: NULL
       TIME_ELAPSED: 65
         TIME_RESET: NULL
             STATUS: enabled
               TYPE: status_counter
            COMMENT: Number of rows inserted
    
  6. 重置dml_inserts计数器,并再次查询INNODB_METRICS表以获取dml_inserts计数器数据。先前报告的%_RESET值,如COUNT_RESETMAX_RESET,将被设置为零。像COUNTMAX_COUNTAVG_COUNT这样的值,从启用计数器开始累积收集数据,不受重置影响。

    mysql> SET GLOBAL innodb_monitor_reset = 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: 3
          MAX_COUNT: 3
          MIN_COUNT: NULL
          AVG_COUNT: 0.03529411764705882
        COUNT_RESET: 0
    MAX_COUNT_RESET: 0
    MIN_COUNT_RESET: NULL
    AVG_COUNT_RESET: 0
       TIME_ENABLED: 2014-12-04 14:18:28
      TIME_DISABLED: NULL
       TIME_ELAPSED: 85
         TIME_RESET: 2014-12-04 14:19:44
             STATUS: enabled
               TYPE: status_counter
            COMMENT: Number of rows inserted
    
  7. 要重置所有计数器值,必须先禁用计数器。禁用计数器会将STATUS值设置为disabled

    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: 3
          MAX_COUNT: 3
          MIN_COUNT: NULL
          AVG_COUNT: 0.030612244897959183
        COUNT_RESET: 0
    MAX_COUNT_RESET: 0
    MIN_COUNT_RESET: NULL
    AVG_COUNT_RESET: 0
       TIME_ENABLED: 2014-12-04 14:18:28
      TIME_DISABLED: 2014-12-04 14:20:06
       TIME_ELAPSED: 98
         TIME_RESET: NULL
             STATUS: disabled
               TYPE: status_counter
            COMMENT: Number of rows inserted
    

    注意

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

  8. 在禁用计数器后,可以使用innodb_monitor_reset_all选项重置所有计数器值。所有值都设置为零或 NULL。

    mysql> SET GLOBAL innodb_monitor_reset_all = 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: 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
    

17.15.7 InnoDB INFORMATION_SCHEMA 临时表信息表

原文:dev.mysql.com/doc/refman/8.0/en/innodb-information-schema-temp-table-info.html

INNODB_TEMP_TABLE_INFO提供有关活动在InnoDB实例中的用户创建的InnoDB临时表的信息。它不提供有关优化器使用的内部InnoDB临时表的信息。

mysql> SHOW TABLES FROM INFORMATION_SCHEMA LIKE 'INNODB_TEMP%';
+---------------------------------------------+
| Tables_in_INFORMATION_SCHEMA (INNODB_TEMP%) |
+---------------------------------------------+
| INNODB_TEMP_TABLE_INFO                      |
+---------------------------------------------+

有关表定义,请参见第 28.4.27 节,“INFORMATION_SCHEMA INNODB_TEMP_TABLE_INFO 表”。

示例 17.12 INNODB_TEMP_TABLE_INFO

此示例演示了INNODB_TEMP_TABLE_INFO表的特性。

  1. 创建一个简单的InnoDB临时表:

    mysql> CREATE TEMPORARY TABLE t1 (c1 INT PRIMARY KEY) ENGINE=INNODB;
    
  2. 查询INNODB_TEMP_TABLE_INFO以查看临时表元数据。

    mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_TEMP_TABLE_INFO\G
    *************************** 1\. row ***************************
                TABLE_ID: 194
                    NAME: #sql7a79_1_0
                  N_COLS: 4
                   SPACE: 182
    

    TABLE_ID是临时表的唯一标识符。NAME列显示临时表的系统生成名称,前缀为“#sql”。列数(N_COLS)为 4,而不是 1,因为InnoDB始终创建三个隐藏表列(DB_ROW_IDDB_TRX_IDDB_ROLL_PTR)。

  3. 重启 MySQL 并查询INNODB_TEMP_TABLE_INFO

    mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_TEMP_TABLE_INFO\G
    

    返回一个空集,因为当服务器关闭时,INNODB_TEMP_TABLE_INFO及其数据不会持久保存到磁盘。

  4. 创建一个新的临时表。

    mysql> CREATE TEMPORARY TABLE t1 (c1 INT PRIMARY KEY) ENGINE=INNODB;
    
  5. 查询INNODB_TEMP_TABLE_INFO以查看临时表元数据。

    mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_TEMP_TABLE_INFO\G
    *************************** 1\. row ***************************
                TABLE_ID: 196
                    NAME: #sql7b0e_1_0
                  N_COLS: 4
                   SPACE: 184
    

    SPACE ID 可能不同,因为它在服务器启动时动态生成。

17.15.8 从 INFORMATION_SCHEMA.FILES 检索 InnoDB 表空间元数据

原文:dev.mysql.com/doc/refman/8.0/en/innodb-information-schema-files-table.html

信息模式FILES表提供有关所有InnoDB表空间类型的元数据,包括 file-per-table tablespaces、general tablespaces、system tablespace、temporary table tablespaces 和 undo tablespaces(如果存在)。

本节提供了InnoDB特定的用法示例。有关信息模式FILES表提供的数据的更多信息,请参阅 Section 28.3.15, “INFORMATION_SCHEMA FILES 表”。

注意

INNODB_TABLESPACESINNODB_DATAFILES表还提供有关InnoDB表空间的元数据,但数据仅限于文件表、一般表和撤销表空间。

此查询从与InnoDB表空间相关的信息模式FILES表的字段中检索有关InnoDB系统表空间的元数据。与InnoDB不相关的FILES列始终返回NULL,并且在查询中被排除。

mysql> SELECT FILE_ID, FILE_NAME, FILE_TYPE, TABLESPACE_NAME, FREE_EXTENTS,
       TOTAL_EXTENTS,  EXTENT_SIZE, INITIAL_SIZE, MAXIMUM_SIZE, AUTOEXTEND_SIZE, DATA_FREE, STATUS ENGINE
       FROM INFORMATION_SCHEMA.FILES WHERE TABLESPACE_NAME LIKE 'innodb_system' \G
*************************** 1\. row ***************************
        FILE_ID: 0
      FILE_NAME: ./ibdata1
      FILE_TYPE: TABLESPACE
TABLESPACE_NAME: innodb_system
   FREE_EXTENTS: 0
  TOTAL_EXTENTS: 12
    EXTENT_SIZE: 1048576
   INITIAL_SIZE: 12582912
   MAXIMUM_SIZE: NULL
AUTOEXTEND_SIZE: 67108864
      DATA_FREE: 4194304
         ENGINE: NORMAL

此查询检索InnoDB文件表和一般表空间的FILE_ID(相当于空间 ID)和FILE_NAME(包括路径信息)。文件表和一般表空间的文件扩展名为.ibd

mysql> SELECT FILE_ID, FILE_NAME FROM INFORMATION_SCHEMA.FILES
       WHERE FILE_NAME LIKE '%.ibd%' ORDER BY FILE_ID;
 +---------+---------------------------------------+
 | FILE_ID | FILE_NAME                             |
 +---------+---------------------------------------+
 |       2 | ./mysql/plugin.ibd                    |
 |       3 | ./mysql/servers.ibd                   |
 |       4 | ./mysql/help_topic.ibd                |
 |       5 | ./mysql/help_category.ibd             |
 |       6 | ./mysql/help_relation.ibd             |
 |       7 | ./mysql/help_keyword.ibd              |
 |       8 | ./mysql/time_zone_name.ibd            |
 |       9 | ./mysql/time_zone.ibd                 |
 |      10 | ./mysql/time_zone_transition.ibd      |
 |      11 | ./mysql/time_zone_transition_type.ibd |
 |      12 | ./mysql/time_zone_leap_second.ibd     |
 |      13 | ./mysql/innodb_table_stats.ibd        |
 |      14 | ./mysql/innodb_index_stats.ibd        |
 |      15 | ./mysql/slave_relay_log_info.ibd      |
 |      16 | ./mysql/slave_master_info.ibd         |
 |      17 | ./mysql/slave_worker_info.ibd         |
 |      18 | ./mysql/gtid_executed.ibd             |
 |      19 | ./mysql/server_cost.ibd               |
 |      20 | ./mysql/engine_cost.ibd               |
 |      21 | ./sys/sys_config.ibd                  |
 |      23 | ./test/t1.ibd                         |
 |      26 | /home/user/test/test/t2.ibd           |
 +---------+---------------------------------------+

此查询检索InnoDB全局临时表空间的FILE_IDFILE_NAME。全局临时表空间文件名以ibtmp为前缀。

mysql> SELECT FILE_ID, FILE_NAME FROM INFORMATION_SCHEMA.FILES
       WHERE FILE_NAME LIKE '%ibtmp%';
+---------+-----------+
| FILE_ID | FILE_NAME |
+---------+-----------+
|      22 | ./ibtmp1  |
+---------+-----------+

同样,InnoDB撤销表空间文件名以undo为前缀。以下查询返回InnoDB撤销表空间的FILE_IDFILE_NAME

mysql> SELECT FILE_ID, FILE_NAME FROM INFORMATION_SCHEMA.FILES
       WHERE FILE_NAME LIKE '%undo%';

17.16 InnoDB 与 MySQL Performance Schema 的集成

原文:dev.mysql.com/doc/refman/8.0/en/innodb-performance-schema.html

17.16.1 使用 Performance Schema 监控 InnoDB 表的 ALTER TABLE 进度

17.16.2 使用 Performance Schema 监控 InnoDB 互斥等待

本节简要介绍了 InnoDB 与 Performance Schema 的集成。有关全面的 Performance Schema 文档,请参阅 第二十九章,MySQL Performance Schema

您可以使用 MySQL Performance Schema 功能 对某些内部 InnoDB 操作进行分析。这种调优主要面向专家用户,他们评估优化策略以克服性能瓶颈。数据库管理员也可以使用此功能进行容量规划,以查看其典型工作负载是否遇到特定 CPU、RAM 和磁盘存储组合的性能瓶颈;如果是,可以判断是否通过增加系统某部分的容量来改善性能。

要使用此功能检查 InnoDB 性能:

  • 您必须对如何使用 Performance Schema 功能 有一般了解。例如,您应该知道如何启用仪器和消费者,以及如何查询 performance_schema 表以检索数据。有关简介概述,请参阅 第 29.1 节,“Performance Schema 快速入门”。

  • 您应该熟悉可用于 InnoDB 的 Performance Schema 仪器。要查看与 InnoDB 相关的仪器,您可以查询 setup_instruments 表,以查找包含 'innodb' 的仪器名称。

    mysql> SELECT *
           FROM performance_schema.setup_instruments
           WHERE NAME LIKE '%innodb%';
    +-------------------------------------------------------+---------+-------+
    | NAME                                                  | ENABLED | TIMED |
    +-------------------------------------------------------+---------+-------+
    | wait/synch/mutex/innodb/commit_cond_mutex             | NO      | NO    |
    | wait/synch/mutex/innodb/innobase_share_mutex          | NO      | NO    |
    | wait/synch/mutex/innodb/autoinc_mutex                 | NO      | NO    |
    | wait/synch/mutex/innodb/buf_pool_mutex                | NO      | NO    |
    | wait/synch/mutex/innodb/buf_pool_zip_mutex            | NO      | NO    |
    | wait/synch/mutex/innodb/cache_last_read_mutex         | NO      | NO    |
    | wait/synch/mutex/innodb/dict_foreign_err_mutex        | NO      | NO    |
    | wait/synch/mutex/innodb/dict_sys_mutex                | NO      | NO    |
    | wait/synch/mutex/innodb/recalc_pool_mutex             | NO      | NO    |
    ...
    | wait/io/file/innodb/innodb_data_file                  | YES     | YES   |
    | wait/io/file/innodb/innodb_log_file                   | YES     | YES   |
    | wait/io/file/innodb/innodb_temp_file                  | YES     | YES   |
    | stage/innodb/alter table (end)                        | YES     | YES   |
    | stage/innodb/alter table (flush)                      | YES     | YES   |
    | stage/innodb/alter table (insert)                     | YES     | YES   |
    | stage/innodb/alter table (log apply index)            | YES     | YES   |
    | stage/innodb/alter table (log apply table)            | YES     | YES   |
    | stage/innodb/alter table (merge sort)                 | YES     | YES   |
    | stage/innodb/alter table (read PK and internal sort)  | YES     | YES   |
    | stage/innodb/buffer pool load                         | YES     | YES   |
    | memory/innodb/buf_buf_pool                            | NO      | NO    |
    | memory/innodb/dict_stats_bg_recalc_pool_t             | NO      | NO    |
    | memory/innodb/dict_stats_index_map_t                  | NO      | NO    |
    | memory/innodb/dict_stats_n_diff_on_level              | NO      | NO    |
    | memory/innodb/other                                   | NO      | NO    |
    | memory/innodb/row_log_buf                             | NO      | NO    |
    | memory/innodb/row_merge_sort                          | NO      | NO    |
    | memory/innodb/std                                     | NO      | NO    |
    | memory/innodb/sync_debug_latches                      | NO      | NO    |
    | memory/innodb/trx_sys_t::rw_trx_ids                   | NO      | NO    |
    ...
    +-------------------------------------------------------+---------+-------+
    155 rows in set (0.00 sec)
    

    有关已仪器化的 InnoDB 对象的其他信息,您可以查询 Performance Schema 实例表,这些表提供有关已仪器化对象的其他信息。与 InnoDB 相关的实例表包括:

    • mutex_instances

    • rwlock_instances

    • cond_instances

    • file_instances

    注意

    InnoDB缓冲池相关的互斥锁和读写锁不包括在此范围内;相同的情况也适用于SHOW ENGINE INNODB MUTEX命令的输出。

    例如,要查看执行文件 I/O 仪表化时性能模式看到的InnoDB文件对象的信息,您可以发出以下查询:

    mysql> SELECT *
           FROM performance_schema.file_instances
           WHERE EVENT_NAME LIKE '%innodb%'\G
    *************************** 1\. row ***************************
     FILE_NAME: /home/dtprice/mysql-8.0/data/ibdata1
    EVENT_NAME: wait/io/file/innodb/innodb_data_file
    OPEN_COUNT: 3
    *************************** 2\. row ***************************
     FILE_NAME: /home/dtprice/mysql-8.0/data/#ib_16384_0.dblwr
    EVENT_NAME: wait/io/file/innodb/innodb_dblwr_file
    OPEN_COUNT: 2
    *************************** 3\. row ***************************
     FILE_NAME: /home/dtprice/mysql-8.0/data/#ib_16384_1.dblwr
    EVENT_NAME: wait/io/file/mysql-8.0/innodb_dblwr_file
    OPEN_COUNT: 2
    ...
    
  • 您应该熟悉存储InnoDB事件数据的performance_schema表。与InnoDB相关事件相关的表包括:

    • 等待事件 表,存储等待事件。

    • 摘要 表,为随时间终止的事件提供聚合信息。摘要表包括 file I/O 摘要表,其中聚合了有关 I/O 操作的信息。

    • 阶段事件 表,存储了InnoDBALTER TABLE和缓冲池加载操作的事件数据。更多信息,请参阅 17.16.1 节,“使用性能模式监控 InnoDB 表的 ALTER TABLE 进度”,以及使用性能模式监控缓冲池加载进度。

    如果您只对与InnoDB相关的对象感兴趣,在查询这些表时,请使用子句WHERE EVENT_NAME LIKE '%innodb%'WHERE NAME LIKE '%innodb%'(根据需要)。

17.16.1 监视使用性能模式的 InnoDB 表的ALTER TABLE 进度

原文:dev.mysql.com/doc/refman/8.0/en/monitor-alter-table-performance-schema.html

您可以使用性能模式监视InnoDB表的ALTER TABLE进度。

有七个阶段事件代表ALTER TABLE 的不同阶段。每个阶段事件报告了整体ALTER TABLE 操作的WORK_COMPLETEDWORK_ESTIMATED的累计值,随着其在不同阶段的进行而不断更新。WORK_ESTIMATED是使用一个公式计算的,该公式考虑了ALTER TABLE 执行的所有工作,并且可能在ALTER TABLE 处理过程中进行修订。WORK_COMPLETEDWORK_ESTIMATED的值是对ALTER TABLE 执行的所有工作的抽象表示。

按顺序,ALTER TABLE 阶段事件包括:

  • stage/innodb/alter table (read PK and internal sort): 当ALTER TABLE处于读取主键阶段时,此阶段处于活动状态。它从WORK_COMPLETED=0开始,并将WORK_ESTIMATED设置为主键中估计的页面数。当阶段完成时,将更新WORK_ESTIMATED为主键中实际的页面数。

  • stage/innodb/alter table (merge sort): 此阶段针对ALTER TABLE操作添加的每个索引重复执行。

  • stage/innodb/alter table (insert): 此阶段针对ALTER TABLE操作添加的每个索引重复执行。

  • stage/innodb/alter table (log apply index): 此阶段包括应用在运行ALTER TABLE时生成的 DML 日志。

  • stage/innodb/alter table (flush): 在此阶段开始之前,根据刷新列表的长度,更新WORK_ESTIMATED以获得更准确的估计。

  • stage/innodb/alter table (log apply table): 此阶段包括应用在运行ALTER TABLE时生成的并发 DML 日志。此阶段的持续时间取决于表更改的程度。如果表上没有运行并发 DML,则此阶段是瞬时的。

  • stage/innodb/alter table (end): 包括在刷新阶段之后出现的任何剩余工作,例如在ALTER TABLE运行时对表执行的 DML 的重新应用。

注意

InnoDBALTER TABLE阶段事件目前不考虑空间索引的添加。

使用性能模式监控ALTER TABLE的示例

以下示例演示了如何启用stage/innodb/alter table%阶段事件工具和相关消费者表来监控ALTER TABLE的进度。有关性能模式阶段事件工具和相关消费者的信息,请参阅第 29.12.5 节,“性能模式阶段事件表”。

  1. 启用stage/innodb/alter%工具:

    mysql> UPDATE performance_schema.setup_instruments
           SET ENABLED = 'YES'
           WHERE NAME LIKE 'stage/innodb/alter%';
    Query OK, 7 rows affected (0.00 sec)
    Rows matched: 7  Changed: 7  Warnings: 0
    
  2. 启用包括events_stages_currentevents_stages_historyevents_stages_history_long的阶段事件消费者表。

    mysql> UPDATE performance_schema.setup_consumers
           SET ENABLED = 'YES'
           WHERE NAME LIKE '%stages%';
    Query OK, 3 rows affected (0.00 sec)
    Rows matched: 3  Changed: 3  Warnings: 0
    
  3. 执行一个ALTER TABLE操作。在此示例中,向 employees 示例数据库的 employees 表中添加一个middle_name列。

    mysql> ALTER TABLE employees.employees ADD COLUMN middle_name varchar(14) AFTER first_name;
    Query OK, 0 rows affected (9.27 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
  4. 通过查询性能模式events_stages_current表来检查ALTER TABLE操作的进度。显示的阶段事件取决于当前正在进行的ALTER TABLE阶段。WORK_COMPLETED列显示已完成的工作。WORK_ESTIMATED列提供了剩余工作的估计。

    mysql> SELECT EVENT_NAME, WORK_COMPLETED, WORK_ESTIMATED
           FROM performance_schema.events_stages_current;
    +------------------------------------------------------+----------------+----------------+
    | EVENT_NAME                                           | WORK_COMPLETED | WORK_ESTIMATED |
    +------------------------------------------------------+----------------+----------------+
    | stage/innodb/alter table (read PK and internal sort) |            280 |           1245 |
    +------------------------------------------------------+----------------+----------------+
    1 row in set (0.01 sec)
    

    如果ALTER TABLE操作已完成,则events_stages_current表将返回一个空集。在这种情况下,您可以查询events_stages_history表来查看已完成操作的事件数据。例如:

    mysql> SELECT EVENT_NAME, WORK_COMPLETED, WORK_ESTIMATED
           FROM performance_schema.events_stages_history;
    +------------------------------------------------------+----------------+----------------+
    | EVENT_NAME                                           | WORK_COMPLETED | WORK_ESTIMATED |
    +------------------------------------------------------+----------------+----------------+
    | stage/innodb/alter table (read PK and internal sort) |            886 |           1213 |
    | stage/innodb/alter table (flush)                     |           1213 |           1213 |
    | stage/innodb/alter table (log apply table)           |           1597 |           1597 |
    | stage/innodb/alter table (end)                       |           1597 |           1597 |
    | stage/innodb/alter table (log apply table)           |           1981 |           1981 |
    +------------------------------------------------------+----------------+----------------+
    5 rows in set (0.00 sec)
    

    如上所示,在ALTER TABLE处理过程中WORK_ESTIMATED值已经修订。初始阶段完成后的估计工作量为 1213。当ALTER TABLE处理完成时,WORK_ESTIMATED被设置为实际值,即 1981。

17.16.2 使用性能模式监视 InnoDB 互斥锁等待

原文:dev.mysql.com/doc/refman/8.0/en/monitor-innodb-mutex-waits-performance-schema.html

互斥锁是代码中使用的一种同步机制,用于强制只有一个线程可以同时访问共享资源。当服务器中的两个或多个线程需要访问同一资源时,这些线程会相互竞争。第一个获得互斥锁的线程会导致其他线程等待,直到锁被释放。

对于被检测的InnoDB互斥锁,可以使用性能模式来监视互斥锁等待。在性能模式表中收集的等待事件数据可以帮助识别具有最多等待或最长总等待时间的互斥锁,例如。

以下示例演示了如何启用InnoDB互斥锁等待工具,如何启用相关的消费者,以及如何查询等待事件数据。

  1. 要查看可用的InnoDB互斥锁等待工具,查询性能模式setup_instruments表。所有InnoDB互斥锁等待工具默认情况下是禁用的。

    mysql> SELECT *
           FROM performance_schema.setup_instruments
           WHERE NAME LIKE '%wait/synch/mutex/innodb%';
    +---------------------------------------------------------+---------+-------+
    | NAME                                                    | ENABLED | TIMED |
    +---------------------------------------------------------+---------+-------+
    | wait/synch/mutex/innodb/commit_cond_mutex               | NO      | NO    |
    | wait/synch/mutex/innodb/innobase_share_mutex            | NO      | NO    |
    | wait/synch/mutex/innodb/autoinc_mutex                   | NO      | NO    |
    | wait/synch/mutex/innodb/autoinc_persisted_mutex         | NO      | NO    |
    | wait/synch/mutex/innodb/buf_pool_flush_state_mutex      | NO      | NO    |
    | wait/synch/mutex/innodb/buf_pool_LRU_list_mutex         | NO      | NO    |
    | wait/synch/mutex/innodb/buf_pool_free_list_mutex        | NO      | NO    |
    | wait/synch/mutex/innodb/buf_pool_zip_free_mutex         | NO      | NO    |
    | wait/synch/mutex/innodb/buf_pool_zip_hash_mutex         | NO      | NO    |
    | wait/synch/mutex/innodb/buf_pool_zip_mutex              | NO      | NO    |
    | wait/synch/mutex/innodb/cache_last_read_mutex           | NO      | NO    |
    | wait/synch/mutex/innodb/dict_foreign_err_mutex          | NO      | NO    |
    | wait/synch/mutex/innodb/dict_persist_dirty_tables_mutex | NO      | NO    |
    | wait/synch/mutex/innodb/dict_sys_mutex                  | NO      | NO    |
    | wait/synch/mutex/innodb/recalc_pool_mutex               | NO      | NO    |
    | wait/synch/mutex/innodb/fil_system_mutex                | NO      | NO    |
    | wait/synch/mutex/innodb/flush_list_mutex                | NO      | NO    |
    | wait/synch/mutex/innodb/fts_bg_threads_mutex            | NO      | NO    |
    | wait/synch/mutex/innodb/fts_delete_mutex                | NO      | NO    |
    | wait/synch/mutex/innodb/fts_optimize_mutex              | NO      | NO    |
    | wait/synch/mutex/innodb/fts_doc_id_mutex                | NO      | NO    |
    | wait/synch/mutex/innodb/log_flush_order_mutex           | NO      | NO    |
    | wait/synch/mutex/innodb/hash_table_mutex                | NO      | NO    |
    | wait/synch/mutex/innodb/ibuf_bitmap_mutex               | NO      | NO    |
    | wait/synch/mutex/innodb/ibuf_mutex                      | NO      | NO    |
    | wait/synch/mutex/innodb/ibuf_pessimistic_insert_mutex   | NO      | NO    |
    | wait/synch/mutex/innodb/log_sys_mutex                   | NO      | NO    |
    | wait/synch/mutex/innodb/log_sys_write_mutex             | NO      | NO    |
    | wait/synch/mutex/innodb/mutex_list_mutex                | NO      | NO    |
    | wait/synch/mutex/innodb/page_zip_stat_per_index_mutex   | NO      | NO    |
    | wait/synch/mutex/innodb/purge_sys_pq_mutex              | NO      | NO    |
    | wait/synch/mutex/innodb/recv_sys_mutex                  | NO      | NO    |
    | wait/synch/mutex/innodb/recv_writer_mutex               | NO      | NO    |
    | wait/synch/mutex/innodb/redo_rseg_mutex                 | NO      | NO    |
    | wait/synch/mutex/innodb/noredo_rseg_mutex               | NO      | NO    |
    | wait/synch/mutex/innodb/rw_lock_list_mutex              | NO      | NO    |
    | wait/synch/mutex/innodb/rw_lock_mutex                   | NO      | NO    |
    | wait/synch/mutex/innodb/srv_dict_tmpfile_mutex          | NO      | NO    |
    | wait/synch/mutex/innodb/srv_innodb_monitor_mutex        | NO      | NO    |
    | wait/synch/mutex/innodb/srv_misc_tmpfile_mutex          | NO      | NO    |
    | wait/synch/mutex/innodb/srv_monitor_file_mutex          | NO      | NO    |
    | wait/synch/mutex/innodb/buf_dblwr_mutex                 | NO      | NO    |
    | wait/synch/mutex/innodb/trx_undo_mutex                  | NO      | NO    |
    | wait/synch/mutex/innodb/trx_pool_mutex                  | NO      | NO    |
    | wait/synch/mutex/innodb/trx_pool_manager_mutex          | NO      | NO    |
    | wait/synch/mutex/innodb/srv_sys_mutex                   | NO      | NO    |
    | wait/synch/mutex/innodb/lock_mutex                      | NO      | NO    |
    | wait/synch/mutex/innodb/lock_wait_mutex                 | NO      | NO    |
    | wait/synch/mutex/innodb/trx_mutex                       | NO      | NO    |
    | wait/synch/mutex/innodb/srv_threads_mutex               | NO      | NO    |
    | wait/synch/mutex/innodb/rtr_active_mutex                | NO      | NO    |
    | wait/synch/mutex/innodb/rtr_match_mutex                 | NO      | NO    |
    | wait/synch/mutex/innodb/rtr_path_mutex                  | NO      | NO    |
    | wait/synch/mutex/innodb/rtr_ssn_mutex                   | NO      | NO    |
    | wait/synch/mutex/innodb/trx_sys_mutex                   | NO      | NO    |
    | wait/synch/mutex/innodb/zip_pad_mutex                   | NO      | NO    |
    | wait/synch/mutex/innodb/master_key_id_mutex             | NO      | NO    |
    +---------------------------------------------------------+---------+-------+
    
  2. 一些InnoDB互斥锁实例是在服务器启动时创建的,只有在服务器启动时还启用了相关的工具时才会被检测。为了确保所有InnoDB互斥锁实例都被检测和启用,将以下performance-schema-instrument规则添加到您的 MySQL 配置文件中:

    performance-schema-instrument='wait/synch/mutex/innodb/%=ON'
    

    如果您不需要所有InnoDB互斥锁的等待事件数据,可以通过向 MySQL 配置文件添加额外的performance-schema-instrument规则来禁用特定工具。例如,要禁用与全文搜索相关的InnoDB互斥锁等待事件工具,添加以下规则:

    performance-schema-instrument='wait/synch/mutex/innodb/fts%=OFF'
    

    注意

    前缀较长的规则(例如wait/synch/mutex/innodb/fts%)优先于前缀较短的规则(例如wait/synch/mutex/innodb/%)。

    在将performance-schema-instrument规则添加到配置文件后,重新启动服务器。除了与全文搜索相关的InnoDB互斥锁之外,所有互斥锁都已启用。要验证,请查询setup_instruments表。对于您启用的工具,ENABLEDTIMED列应设置为YES

    mysql> SELECT *
           FROM performance_schema.setup_instruments
           WHERE NAME LIKE '%wait/synch/mutex/innodb%';
    +-------------------------------------------------------+---------+-------+
    | NAME                                                  | ENABLED | TIMED |
    +-------------------------------------------------------+---------+-------+
    | wait/synch/mutex/innodb/commit_cond_mutex             | YES     | YES   |
    | wait/synch/mutex/innodb/innobase_share_mutex          | YES     | YES   |
    | wait/synch/mutex/innodb/autoinc_mutex                 | YES     | YES   |
    ...
    | wait/synch/mutex/innodb/master_key_id_mutex           | YES     | YES   |
    +-------------------------------------------------------+---------+-------+
    49 rows in set (0.00 sec)
    
  3. 通过更新setup_consumers表来启用等待事件消费者。等待事件消费者默认情况下是禁用的。

    mysql> UPDATE performance_schema.setup_consumers
           SET enabled = 'YES'
           WHERE name like 'events_waits%';
    Query OK, 3 rows affected (0.00 sec)
    Rows matched: 3  Changed: 3  Warnings: 0
    

    您可以通过查询setup_consumers表来验证等待事件消费者是否已启用。events_waits_currentevents_waits_historyevents_waits_history_long消费者应该已启用。

    mysql> SELECT * FROM performance_schema.setup_consumers;
    +----------------------------------+---------+
    | NAME                             | ENABLED |
    +----------------------------------+---------+
    | events_stages_current            | NO      |
    | events_stages_history            | NO      |
    | events_stages_history_long       | NO      |
    | events_statements_current        | YES     |
    | events_statements_history        | YES     |
    | events_statements_history_long   | NO      |
    | events_transactions_current      | YES     |
    | events_transactions_history      | YES     |
    | events_transactions_history_long | NO      |
    | events_waits_current             | YES     |
    | events_waits_history             | YES     |
    | events_waits_history_long        | YES     |
    | global_instrumentation           | YES     |
    | thread_instrumentation           | YES     |
    | statements_digest                | YES     |
    +----------------------------------+---------+
    15 rows in set (0.00 sec)
    
  4. 一旦仪器和消费者已启用,请运行您想要监视的工作负载。在本示例中,使用mysqlslap负载仿真客户端来模拟工作负载。

    $> ./mysqlslap --auto-generate-sql --concurrency=100 --iterations=10 
           --number-of-queries=1000 --number-char-cols=6 --number-int-cols=6;
    
  5. 查询等待事件数据。在本示例中,等待事件数据是从events_waits_summary_global_by_event_name表中查询的,该表汇总了events_waits_currentevents_waits_historyevents_waits_history_long表中的数据。数据按事件名称(EVENT_NAME)进行汇总,这是产生事件的仪器的名称。汇总的数据包括:

    • COUNT_STAR

      总结的等待事件数量。

    • SUM_TIMER_WAIT

      总结的定时等待事件的总等待时间。

    • MIN_TIMER_WAIT

      总结的定时等待事件的最小等待时间。

    • AVG_TIMER_WAIT

      总结的定时等待事件的平均等待时间。

    • MAX_TIMER_WAIT

      总结的定时等待事件的最大等待时间。

    以下查询返回仪器名称(EVENT_NAME)、等待事件数量(COUNT_STAR)以及该仪器事件的总等待时间(SUM_TIMER_WAIT)。由于默认情况下等待时间以皮秒(万亿分之一秒)计时,等待时间除以 1000000000 以显示以毫秒为单位的等待时间。数据按照总结的等待事件数量(COUNT_STAR)降序呈现。您可以调整ORDER BY子句以按照总等待时间对数据进行排序。

    mysql> SELECT EVENT_NAME, COUNT_STAR, SUM_TIMER_WAIT/1000000000 SUM_TIMER_WAIT_MS
           FROM performance_schema.events_waits_summary_global_by_event_name
           WHERE SUM_TIMER_WAIT > 0 AND EVENT_NAME LIKE 'wait/synch/mutex/innodb/%'
           ORDER BY COUNT_STAR DESC;
    +---------------------------------------------------------+------------+-------------------+
    | EVENT_NAME                                              | COUNT_STAR | SUM_TIMER_WAIT_MS |
    +---------------------------------------------------------+------------+-------------------+
    | wait/synch/mutex/innodb/trx_mutex                       |     201111 |           23.4719 |
    | wait/synch/mutex/innodb/fil_system_mutex                |      62244 |            9.6426 |
    | wait/synch/mutex/innodb/redo_rseg_mutex                 |      48238 |            3.1135 |
    | wait/synch/mutex/innodb/log_sys_mutex                   |      46113 |            2.0434 |
    | wait/synch/mutex/innodb/trx_sys_mutex                   |      35134 |         1068.1588 |
    | wait/synch/mutex/innodb/lock_mutex                      |      34872 |         1039.2589 |
    | wait/synch/mutex/innodb/log_sys_write_mutex             |      17805 |         1526.0490 |
    | wait/synch/mutex/innodb/dict_sys_mutex                  |      14912 |         1606.7348 |
    | wait/synch/mutex/innodb/trx_undo_mutex                  |      10634 |            1.1424 |
    | wait/synch/mutex/innodb/rw_lock_list_mutex              |       8538 |            0.1960 |
    | wait/synch/mutex/innodb/buf_pool_free_list_mutex        |       5961 |            0.6473 |
    | wait/synch/mutex/innodb/trx_pool_mutex                  |       4885 |         8821.7496 |
    | wait/synch/mutex/innodb/buf_pool_LRU_list_mutex         |       4364 |            0.2077 |
    | wait/synch/mutex/innodb/innobase_share_mutex            |       3212 |            0.2650 |
    | wait/synch/mutex/innodb/flush_list_mutex                |       3178 |            0.2349 |
    | wait/synch/mutex/innodb/trx_pool_manager_mutex          |       2495 |            0.1310 |
    | wait/synch/mutex/innodb/buf_pool_flush_state_mutex      |       1318 |            0.2161 |
    | wait/synch/mutex/innodb/log_flush_order_mutex           |       1250 |            0.0893 |
    | wait/synch/mutex/innodb/buf_dblwr_mutex                 |        951 |            0.0918 |
    | wait/synch/mutex/innodb/recalc_pool_mutex               |        670 |            0.0942 |
    | wait/synch/mutex/innodb/dict_persist_dirty_tables_mutex |        345 |            0.0414 |
    | wait/synch/mutex/innodb/lock_wait_mutex                 |        303 |            0.1565 |
    | wait/synch/mutex/innodb/autoinc_mutex                   |        196 |            0.0213 |
    | wait/synch/mutex/innodb/autoinc_persisted_mutex         |        196 |            0.0175 |
    | wait/synch/mutex/innodb/purge_sys_pq_mutex              |        117 |            0.0308 |
    | wait/synch/mutex/innodb/srv_sys_mutex                   |         94 |            0.0077 |
    | wait/synch/mutex/innodb/ibuf_mutex                      |         22 |            0.0086 |
    | wait/synch/mutex/innodb/recv_sys_mutex                  |         12 |            0.0008 |
    | wait/synch/mutex/innodb/srv_innodb_monitor_mutex        |          4 |            0.0009 |
    | wait/synch/mutex/innodb/recv_writer_mutex               |          1 |            0.0005 |
    +---------------------------------------------------------+------------+-------------------+
    

    注意

    前面的结果集包括在启动过程中产生的等待事件数据。为了排除这些数据,您可以在启动后立即截断events_waits_summary_global_by_event_name表,然后再运行您的工作负载。但是,��断操作本身可能会产生微不足道的等待事件数据。

    mysql> TRUNCATE performance_schema.events_waits_summary_global_by_event_name;
    

17.17 InnoDB 监视器

原文:dev.mysql.com/doc/refman/8.0/en/innodb-monitors.html

17.17.1 InnoDB Monitor Types

17.17.2 启用 InnoDB 监视器

17.17.3 InnoDB Standard Monitor and Lock Monitor Output

InnoDB 监视器提供有关 InnoDB 内部状态的信息。这些信息对性能调优很有用。

17.17.1 InnoDB 监视器类型

原文:dev.mysql.com/doc/refman/8.0/en/innodb-monitor-types.html

有两种类型的InnoDB监视器:

  • 标准InnoDB监视器显示以下类型的信息:

    • 主后台线程完成的工作

    • 信号量等待

    • 最近的外键和死锁错误数据

    • 事务的锁等待

    • 活动事务持有的表和记录锁

    • 待处理的 I/O 操作及相关统计信息

    • 插入缓冲区和自适应哈希索引统计信息

    • 重做日志数据

    • 缓冲池统计信息

    • 行操作数据

  • InnoDB锁监视器会在标准InnoDB监视器输出中打印额外的锁信息。

17.17.2 启用 InnoDB 监视器

原文:dev.mysql.com/doc/refman/8.0/en/innodb-enabling-monitors.html

当为定期输出启用 InnoDB 监视器时,InnoDB 每隔约 15 秒将输出写入到 mysqld 服务器标准错误输出 (stderr)。

InnoDB 将监视器输出发送到 stderr 而不是 stdout 或固定大小的内存缓冲区,以避免潜在的缓冲区溢出。

在 Windows 上,stderr 通常会被定向到默认日志文件,除非另有配置。如果想将输出定向到控制台窗口而不是错误日志,请在控制台窗口中的命令提示符下使用 --console 选项启动服务器。更多信息,请参见 Windows 上的默认错误日志目的地。

在 Unix 和类 Unix 系统上,stderr 通常会被定向到终端,除非另有配置。更多信息,请参见 Unix 和类 Unix 系统上的默认错误日志目的地。

只有在实际需要查看监视器信息时才应启用 InnoDB 监视器,因为输出生成会导致一定的性能降低。此外,如果监视器输出被定向到错误日志,如果忘记后续禁用监视器,日志可能会变得非常庞大。

注意

为了帮助故障排除,在某些条件下,InnoDB 会临时启用标准 InnoDB 监视器输出。更多信息,请参见 第 17.21 节,“InnoDB 故障排除”。

InnoDB 监视器输出以包含时间戳和监视器名称的标题开头。例如:

=====================================
2014-10-16 18:37:29 0x7fc2a95c1700 INNODB MONITOR OUTPUT
=====================================

标准 InnoDB 监视器的标题 (INNODB MONITOR OUTPUT) 也用于锁监视器,因为后者会生成相同的输出并附加额外的锁信息。

innodb_status_outputinnodb_status_output_locks 系统变量用于启用标准 InnoDB 监视器和 InnoDB 锁监视器。

需要 PROCESS 权限才能启用或禁用 InnoDB 监视器。

启用标准 InnoDB 监视器

通过将 innodb_status_output 系统变量设置为 ON 来启用标准 InnoDB 监视器。

SET GLOBAL innodb_status_output=ON;

要禁用标准 InnoDB 监视器,请将 innodb_status_output 设置为 OFF

当关闭服务器时,innodb_status_output 变量将设置为默认值 OFF

启用 InnoDB 锁监视器

InnoDB 锁监视器数据与 InnoDB 标准监视器输出一起打印。必须同时启用 InnoDB 标准监视器和 InnoDB 锁监视器,才能定期打印 InnoDB 锁监视器数据。

要启用 InnoDB 锁监视器,请将 innodb_status_output_locks 系统变量设置为 ON。必须同时启用 InnoDB 标准监视器和 InnoDB 锁监视器,才能定期打印 InnoDB 锁监视器数据:

SET GLOBAL innodb_status_output=ON;
SET GLOBAL innodb_status_output_locks=ON;

要禁用 InnoDB 锁监视器,请将 innodb_status_output_locks 设置为 OFF。将 innodb_status_output 设置为 OFF 也会禁用 InnoDB 标准监视器。

当关闭服务器时,innodb_status_outputinnodb_status_output_locks 变量将设置为默认值 OFF

注意

要为 SHOW ENGINE INNODB STATUS 输出启用 InnoDB 锁监视器,只需启用 innodb_status_output_locks 即可。

根据需要获取标准 InnoDB 监视器输出

作为定期输出标准 InnoDB 监视器的替代方法,您可以根据需要使用 SHOW ENGINE INNODB STATUS SQL 语句获取标准 InnoDB 监视器输出,该语句将输出提取到您的客户端程序。如果您使用 mysql 交互式客户端,则如果将通常的分号语句终止符替换为 \G,输出将更易读:

mysql> SHOW ENGINE INNODB STATUS\G

SHOW ENGINE INNODB STATUS 输出还包括 InnoDB 锁监视器数据,如果启用了 InnoDB 锁监视器。

将标准 InnoDB 监视器输出定向到状态文件

可以通过在启动时指定 --innodb-status-file 选项来启用并将标准 InnoDB 监视器输出定向到状态文件。使用此选项时,InnoDB 在数据目录中创建一个名为 innodb_status.*pid* 的文件,并每隔约 15 秒将输出写入其中。

当服务器正常关闭时,InnoDB 会删除状态文件。如果发生异常关闭,则可能需要手动删除状态文件。

--innodb-status-file 选项仅供临时使用,因为输出生成可能会影响性能,并且随着时间推移,innodb_status.*pid* 文件可能会变得非常大。

17.17.3 InnoDB 标准监视器和锁监视器输出

原文:dev.mysql.com/doc/refman/8.0/en/innodb-standard-monitor.html

锁监视器与标准监视器相同,只是它包含额外的锁信息。启用周期性输出的任一监视器会打开相同的输出流,但如果启用了锁监视器,则该流会包含额外的信息。例如,如果你启用了标准监视器和锁监视器,那么会打开一个单一的输出流。该流会包含额外的锁信息,直到你禁用锁监视器。

使用SHOW ENGINE INNODB STATUS语句生成的标准监视器输出在达到 1MB 时受到限制。此限制不适用于写入服务器标准错误输出(stderr)的输出。

示例标准监视器输出:

mysql> SHOW ENGINE INNODB STATUS\G
*************************** 1\. row ***************************
  Type: InnoDB
  Name:
Status:
=====================================
2018-04-12 15:14:08 0x7f971c063700 INNODB MONITOR OUTPUT
=====================================
Per second averages calculated from the last 4 seconds
-----------------
BACKGROUND THREAD
-----------------
srv_master_thread loops: 15 srv_active, 0 srv_shutdown, 1122 srv_idle
srv_master_thread log flush and writes: 0
----------
SEMAPHORES
----------
OS WAIT ARRAY INFO: reservation count 24
OS WAIT ARRAY INFO: signal count 24
RW-shared spins 4, rounds 8, OS waits 4
RW-excl spins 2, rounds 60, OS waits 2
RW-sx spins 0, rounds 0, OS waits 0
Spin rounds per wait: 2.00 RW-shared, 30.00 RW-excl, 0.00 RW-sx
------------------------
LATEST FOREIGN KEY ERROR
------------------------
2018-04-12 14:57:24 0x7f97a9c91700 Transaction:
TRANSACTION 7717, ACTIVE 0 sec inserting
mysql tables in use 1, locked 1
4 lock struct(s), heap size 1136, 3 row lock(s), undo log entries 3
MySQL thread id 8, OS thread handle 140289365317376, query id 14 localhost root update
INSERT INTO child VALUES (NULL, 1), (NULL, 2), (NULL, 3), (NULL, 4), (NULL, 5), (NULL, 6)
Foreign key constraint fails for table `test`.`child`:
,
  CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`) ON DELETE
  CASCADE ON UPDATE CASCADE
Trying to add in child table, in index par_ind tuple:
DATA TUPLE: 2 fields;
 0: len 4; hex 80000003; asc     ;;
 1: len 4; hex 80000003; asc     ;;

But in parent table `test`.`parent`, in index PRIMARY,
the closest match we can find is record:
PHYSICAL RECORD: n_fields 3; compact format; info bits 0
 0: len 4; hex 80000004; asc     ;;
 1: len 6; hex 000000001e19; asc       ;;
 2: len 7; hex 81000001110137; asc       7;;

------------
TRANSACTIONS
------------
Trx id counter 7748
Purge done for trx's n:o < 7747 undo n:o < 0 state: running but idle
History list length 19
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 421764459790000, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 7747, ACTIVE 23 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 9, OS thread handle 140286987249408, query id 51 localhost root updating
DELETE FROM t WHERE i = 1
------- TRX HAS BEEN WAITING 23 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 4 page no 4 n bits 72 index GEN_CLUST_INDEX of table `test`.`t`
trx id 7747 lock_mode X waiting
Record lock, heap no 3 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
 0: len 6; hex 000000000202; asc       ;;
 1: len 6; hex 000000001e41; asc      A;;
 2: len 7; hex 820000008b0110; asc        ;;
 3: len 4; hex 80000001; asc     ;;

------------------
TABLE LOCK table `test`.`t` trx id 7747 lock mode IX
RECORD LOCKS space id 4 page no 4 n bits 72 index GEN_CLUST_INDEX of table `test`.`t`
trx id 7747 lock_mode X waiting
Record lock, heap no 3 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
 0: len 6; hex 000000000202; asc       ;;
 1: len 6; hex 000000001e41; asc      A;;
 2: len 7; hex 820000008b0110; asc        ;;
 3: len 4; hex 80000001; asc     ;;

--------
FILE I/O
--------
I/O thread 0 state: waiting for i/o request (insert buffer thread)
I/O thread 1 state: waiting for i/o request (log thread)
I/O thread 2 state: waiting for i/o request (read thread)
I/O thread 3 state: waiting for i/o request (read thread)
I/O thread 4 state: waiting for i/o request (read thread)
I/O thread 5 state: waiting for i/o request (read thread)
I/O thread 6 state: waiting for i/o request (write thread)
I/O thread 7 state: waiting for i/o request (write thread)
I/O thread 8 state: waiting for i/o request (write thread)
I/O thread 9 state: waiting for i/o request (write thread)
Pending normal aio reads: [0, 0, 0, 0] , aio writes: [0, 0, 0, 0] ,
 ibuf aio reads:, log i/o's:, sync i/o's:
Pending flushes (fsync) log: 0; buffer pool: 0
833 OS file reads, 605 OS file writes, 208 OS fsyncs
0.00 reads/s, 0 avg bytes/read, 0.00 writes/s, 0.00 fsyncs/s
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 0, seg size 2, 0 merges
merged operations:
 insert 0, delete mark 0, delete 0
discarded operations:
 insert 0, delete mark 0, delete 0
Hash table size 553253, node heap has 0 buffer(s)
Hash table size 553253, node heap has 1 buffer(s)
Hash table size 553253, node heap has 3 buffer(s)
Hash table size 553253, node heap has 0 buffer(s)
Hash table size 553253, node heap has 0 buffer(s)
Hash table size 553253, node heap has 0 buffer(s)
Hash table size 553253, node heap has 0 buffer(s)
Hash table size 553253, node heap has 0 buffer(s)
0.00 hash searches/s, 0.00 non-hash searches/s
---
LOG
---
Log sequence number          19643450
Log buffer assigned up to    19643450
Log buffer completed up to   19643450
Log written up to            19643450
Log flushed up to            19643450
Added dirty pages up to      19643450
Pages flushed up to          19643450
Last checkpoint at           19643450
129 log i/o's done, 0.00 log i/o's/second
----------------------
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 2198863872
Dictionary memory allocated 409606
Buffer pool size   131072
Free buffers       130095
Database pages     973
Old database pages 0
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 810, created 163, written 404
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
Buffer pool hit rate 1000 / 1000, young-making rate 0 / 1000 not 0 / 1000
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 973, unzip_LRU len: 0
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
----------------------
INDIVIDUAL BUFFER POOL INFO
----------------------
---BUFFER POOL 0
Buffer pool size   65536
Free buffers       65043
Database pages     491
Old database pages 0
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 411, created 80, written 210
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
Buffer pool hit rate 1000 / 1000, young-making rate 0 / 1000 not 0 / 1000
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 491, unzip_LRU len: 0
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
---BUFFER POOL 1
Buffer pool size   65536
Free buffers       65052
Database pages     482
Old database pages 0
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 399, created 83, written 194
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: 482, unzip_LRU len: 0
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
--------------
ROW OPERATIONS
--------------
0 queries inside InnoDB, 0 queries in queue
0 read views open inside InnoDB
Process ID=5772, Main thread ID=140286437054208 , state=sleeping
Number of rows inserted 57, updated 354, deleted 4, read 4421
0.00 inserts/s, 0.00 updates/s, 0.00 deletes/s, 0.00 reads/s
----------------------------
END OF INNODB MONITOR OUTPUT
============================

标准监视器输出部分

有关标准监视器报告的每个指标的描述,请参考 Oracle Enterprise Manager for MySQL Database User's Guide 中的指标章节。

  • 状态

    本部分显示时间戳、监视器名称以及每秒平均值基于的秒数。秒数是当前时间与上次打印InnoDB监视器输出之间的经过时间。

  • 后台线程

    srv_master_thread行显示了主后台线程执行的工作。

  • 信号量

    本部分报告了等待信号量的线程以及线程需要自旋或在互斥量或读写锁信号量上等待的次数的统计信息。大量等待信号量的线程可能是由于磁盘 I/O 或InnoDB内部争用问题引起的。争用可能是由于查询的重度并行性或操作系统线程调度问题引起的。在这种情况下,将innodb_thread_concurrency系统变量设置为小于默认值可能有所帮助。每次等待的自旋轮数行显示了每个 OS 等待互斥量的自旋锁轮数。

    互斥量指标由SHOW ENGINE INNODB MUTEX报告。

  • 最新外键错误

    本部分提供了关于最近的外键约束错误的信息。如果没有发生此类错误,则不会显示。内容包括失败的语句以及有关失败约束的信息以及引用和引用表的信息。

  • 最新检测到的死锁

    这一部分提供了关于最近死锁的信息。如果没有发生死锁,则不会显示。内容显示了涉及的事务、每个事务试图执行的语句、它们拥有和需要的锁,以及InnoDB决定回滚以打破死锁的事务。本节中报告的锁模式在第 17.7.1 节,“InnoDB 锁定”中有解释。

  • 事务

    如果此部分报告锁等待,您的应用程序可能存在锁争用。输出还可以帮助跟踪事务死锁的原因。

  • 文件 I/O

    这一部分提供了关于InnoDB用于执行各种类型 I/O 的线程的信息。其中前几个专门用于一般的InnoDB处理。内容还显示了待处理 I/O 操作的信息和 I/O 性能的统计信息。

    这些线程的数量由innodb_read_io_threadsinnodb_write_io_threads参数控制。请参阅第 17.14 节,“InnoDB 启动选项和系统变量”。

  • 插入缓冲区和自适应哈希索引

    这一部分显示了InnoDB插入缓冲区(也称为更改缓冲区)和自适应哈希索引的状态。

    有关更多信息,请参阅第 17.5.2 节,“更改缓冲区”和第 17.5.3 节,“自适应哈希索引”。

  • 日志

    这一部分显示了关于InnoDB日志的信息。内容包括当前日志序列号、日志已刷新到磁盘的位置,以及InnoDB上次进行检查点的位置。 (参见第 17.11.3 节,“InnoDB 检查点”.) 本节还显示了有关待写入和写入性能统计的信息。

  • 缓冲池和内存

    这一部分为您提供了关于读取和写入页面的统计信息。您可以根据这些数字计算出您的查询当前正在执行多少数据文件 I/O 操作。

    有关缓冲池统计描述,请参阅使用 InnoDB 标准监视器监视缓冲池。有关缓冲池操作的其他信息,请参阅第 17.5.1 节,“缓冲池”。

  • 行操作

    这一部分展示了主线程正在做的事情,包括每种类型的行操作的数量和性能率。

17.18 InnoDB 备份和恢复

原文:dev.mysql.com/doc/refman/8.0/en/innodb-backup-recovery.html

17.18.1 InnoDB 备份

17.18.2 InnoDB 恢复

本节涵盖与InnoDB备份和恢复相关的主题。

  • 有关适用于InnoDB的备份技术的信息,请参阅第 17.18.1 节,“InnoDB 备份”。

  • 有关时间点恢复、从磁盘故障或损坏中恢复以及InnoDB如何执行崩溃恢复的信息,请参阅第 17.18.2 节,“InnoDB 恢复”。

17.18.1 InnoDB 备份

原文:dev.mysql.com/doc/refman/8.0/en/innodb-backup.html

安全数据库管理的关键是定期备份。根据您的数据量、MySQL 服务器数量和数据库工作量,您可以单独或结合使用以下备份技术:使用MySQL Enterprise Backup进行热备份;在 MySQL 服务器关闭时通过复制文件进行冷备份;使用mysqldump进行逻辑备份,适用于较小的数据量或记录模式对象的结构。热备份和冷备份是物理备份,复制实际数据文件,可以直接被mysqld服务器用于更快的恢复。

使用MySQL Enterprise Backup是备份InnoDB数据的推荐方法。

注意

InnoDB不支持使用第三方备份工具还原的数据库。

热备份

mysqlbackup命令是 MySQL Enterprise Backup 组件的一部分,允许您备份运行中的 MySQL 实例,包括InnoDB表,在产生一致的数据库快照的同时最小化对操作的干扰。当mysqlbackup复制InnoDB表时,对InnoDB表的读写可以继续。MySQL Enterprise Backup 还可以创建压缩备份文件,并备份表和数据库的子集。结合 MySQL 二进制日志,用户可以执行按时间点恢复。MySQL Enterprise Backup 是 MySQL Enterprise 订阅的一部分。有关更多详细信息,请参见 Section 32.1, “MySQL Enterprise Backup Overview”。

冷备份

如果可以关闭 MySQL 服务器,可以进行包含InnoDB用于管理其表的所有文件的物理备份。使用以下步骤:

  1. 执行慢关闭 MySQL 服务器,并确保它在没有错误的情况下停止。

  2. 将所有InnoDB数据文件(ibdata文件和.ibd文件)复制到安全位置。

  3. 将所有InnoDB重做日志文件(MySQL 8.0.30 及更高版本中的#ib_redo*N*文件或早期版本中的ib_logfile文件)复制到安全位置。

  4. 将您的my.cnf配置文件或文件复制到安全位置。

使用 mysqldump 进行逻辑备份

除了物理备份之外,建议您定期使用mysqldump转储表格,创建逻辑备份。二进制文件可能会在您没有注意到的情况下损坏。转储的表格存储在人类可读的文本文件中,因此更容易发现表格损坏。此外,由于格式更简单,严重数据损坏的机会更小。mysqldump还具有--single-transaction选项,可以在不锁定其他客户端的情况下创建一致的快照。请参阅第 9.3.1 节,“建立备份策略”。

复制功能适用于InnoDB表格,因此您可以使用 MySQL 复制功能在需要高可用性的数据库站点保留数据库副本。请参阅第 17.19 节,“InnoDB 和 MySQL 复制”。

17.18.2 InnoDB 恢复

原文:dev.mysql.com/doc/refman/8.0/en/innodb-recovery.html

本节描述了InnoDB恢复。主题包括:

  • 时间点恢复

  • 从数据损坏或磁盘故障中恢复

  • InnoDB ��溃恢复

  • 崩溃恢复中的表空间发现

时间点恢复

要将InnoDB数据库从物理备份的时间恢复到当前状态,必须在进行备份之前启用 MySQL 服务器的二进制日志记录。在恢复备份后实现时间点恢复,可以应用在备份后发生的二进制日志更改。参见第 9.5 节,“时间点(增量)恢复” Recovery")。

从数据损坏或磁盘故障中恢复

如果您的数据库损坏或磁盘故障发生,您必须使用备份执行恢复。在损坏的情况下,首先找到一个没有损坏的备份。恢复基本备份后,使用mysqlbinlogmysql从二进制日志文件中执行时间点恢复,以恢复备份后发生的更改。

在某些数据库损坏的情况下,只需转储、删除和重新创建一个或几个损坏的表即可。您可以使用CHECK TABLE语句来检查表是否损坏,尽管CHECK TABLE自然无法检测到每种可能的损坏。

在某些情况下,表面上的数据库页损坏实际上是由于操作系统损坏了自己的文件缓存,磁盘上的数据可能是正常的。最好先尝试重新启动计算机。这样做可能会消除看起来是数据库页损坏的错误。如果 MySQL 由于InnoDB一致性问题而仍然无法启动,请参见第 17.21.3 节,“强制 InnoDB 恢复”,了解在恢复模式下启动实例的步骤,这样可以让您转储数据。

InnoDB 崩溃恢复

要从意外的 MySQL 服务器退出中恢复,唯一的要求是重新启动 MySQL 服务器。InnoDB会自动检查日志并将数据库回滚到当前状态。InnoDB会自动回滚在崩溃时存在的未提交事务。

InnoDB 崩溃恢复包括几个步骤:

  • 表空间发现

    表空间发现是InnoDB用来识别需要重做日志应用的表空间的过程。请参阅崩溃恢复期间的表空间发现。

  • 重做日志应用

    重做日志应用是在初始化期间执行的,在接受任何连接之前。如果在关闭或崩溃时从缓冲池中的所有更改都被刷新到表空间(ibdata**.ibd文件),则会跳过重做日志应用。如果在启动时重做日志文件丢失,InnoDB也会跳过重做日志应用。

    • 每次自增计数器值发生变化时,当前最大自增计数器值都会被写入重做日志,使其具有崩溃安全性。在恢复过程中,InnoDB会扫描重做日志以收集计数器值的变化,并将这些变化应用于内存中的表对象。

      有关InnoDB如何处理自增值的更多信息,请参阅第 17.6.1.6 节,“InnoDB 中的 AUTO_INCREMENT 处理”,以及 InnoDB AUTO_INCREMENT 计数器初始化。

    • 当遇到索引树损坏时,InnoDB会将一个损坏标志写入重做日志,使得损坏标志具有崩溃安全性。InnoDB还会在每次检查点时将内存中的损坏标志数据写入引擎私有系统表中。在恢复过程中,InnoDB会从两个位置读取损坏标志,并在标记内存表和索引对象为损坏之前合并结果。

    • 不建议删除重做日志以加快恢复速度,即使可以接受一些数据丢失。只有在干净关闭后,将innodb_fast_shutdown设置为01后才应考虑删除重做日志。

  • 回滚未完成的事务

    未完成的事务是在意外退出或快速关闭时处于活动状态的任何事务。回滚未完成事务所需的时间可能是事务被中断前活动时间的三到四倍,取决于服务器负载。

    无法取消正在回滚的事务。在极端情况下,当预计回滚事务需要花费异常长的时间时,通过使用设置为3或更高的innodb_force_recovery选项启动InnoDB可能更快。请参阅第 17.21.3 节,“强制 InnoDB 恢复”。

  • 更改缓冲区合并

    将更改缓冲区(系统表空间的一部分)中的更改应用到辅助索引的叶页,因为索引页被读取到缓冲池中。

  • 清理

    删除对活动事务不再可见的已标记删除记录。

在重做日志应用后的步骤不依赖于重做日志(除了用于记录写入),并与正常处理并行执行。其中,只有不完整事务的回滚对于崩溃恢复是特殊的。插入缓冲区合并和清理是在正常处理期间执行的。

在重做日志应用之后,InnoDB尽早尝试接受连接,以减少停机时间。作为崩溃恢复的一部分,InnoDB回滚了在服务器退出时未提交或处于XA PREPARE状态的事务。回滚由后台线程执行,并与新连接的事务并行执行。在回滚操作完成之前,新连接可能会与恢复的事务发生锁定冲突。

在大多数情况下,即使 MySQL 服务器在繁忙活动中意外关闭,恢复过程会自动发生,DBA 不需要采取任何行动。如果硬件故障或严重系统错误损坏了InnoDB数据,MySQL 可能会拒绝启动。在这种情况下,请参阅第 17.21.3 节,“强制 InnoDB 恢复”。

有关二进制日志和InnoDB崩溃恢复的信息,请参阅第 7.4.4 节,“二进制日志”。

在崩溃恢复期间的表空间发现

如果在恢复过程中,InnoDB遇到自上次检查点以来写入的重做日志,则必须将重做日志应用于受影响的表空间。在恢复期间识别受影响表空间的过程称为表空间发现

表空间发现依赖于innodb_directories设置,该设置定义了在启动时扫描表空间文件的目录。innodb_directories的默认设置为 NULL,但在 InnoDB 构建启动时要扫描的目录列表时,始终会将由innodb_data_home_dirinnodb_undo_directorydatadir定义的目录附加到innodb_directories参数值上。这些目录会被附加,无论是否明确指定了innodb_directories设置。如果在重做日志中引用的任何表空间文件之前未发现,恢复将终止。

17.19 InnoDB 和 MySQL 复制

原文:dev.mysql.com/doc/refman/8.0/en/innodb-and-mysql-replication.html

可以以副本上的存储引擎与源端不同的方式使用复制。例如,您可以将对源端上的InnoDB表的修改复制到副本上的MyISAM表。有关更多信息,请参见第 19.4.4 节,“使用不同源和副本存储引擎的复制”。

有关设置副本的信息,请参见第 19.1.2.6 节,“设置副本”和第 19.1.2.5 节,“选择数据快照方法”。要创建一个新的副本而不关闭源端或现有副本,请使用 MySQL 企业备份产品。

在源端失败的事务不会影响复制。MySQL 复制基于二进制日志,MySQL 在其中写入修改数据的 SQL 语句。失败的事务(例如,由于外键违反或回滚而失败)不会被写入二进制日志,因此不会被发送到副本。参见第 15.3.1 节,“START TRANSACTION,COMMIT 和 ROLLBACK 语句”。

复制和级联。 仅当源端和副本上共享外键关系的表都使用InnoDB时,源端上InnoDB表的级联操作才会在副本上执行。无论您使用基于语句还是基于行的复制,这都是正确的。假设您已经开始了复制,然后在源端创建两个表,其中InnoDB被定义为默认存储引擎,使用以下CREATE TABLE语句:

CREATE TABLE fc1 (
    i INT PRIMARY KEY,
    j INT
);

CREATE TABLE fc2 (
    m INT PRIMARY KEY,
    n INT,
    FOREIGN KEY ni (n) REFERENCES fc1 (i)
        ON DELETE CASCADE
);

如果副本将MyISAM定义为默认存储引擎,则在副本上创建相同的表,但它们使用MyISAM存储引擎,并且FOREIGN KEY选项被忽略。现在我们在源端的表中插入一些行:

source> INSERT INTO fc1 VALUES (1, 1), (2, 2);
Query OK, 2 rows affected (0.09 sec)
Records: 2  Duplicates: 0  Warnings: 0

source> INSERT INTO fc2 VALUES (1, 1), (2, 2), (3, 1);
Query OK, 3 rows affected (0.19 sec)
Records: 3  Duplicates: 0  Warnings: 0

此时,在源端和副本上,fc1表包含 2 行,fc2表包含 3 行,如下所示:

source> SELECT * FROM fc1;
+---+------+
| i | j    |
+---+------+
| 1 |    1 |
| 2 |    2 |
+---+------+
2 rows in set (0.00 sec)

source> SELECT * FROM fc2;
+---+------+
| m | n    |
+---+------+
| 1 |    1 |
| 2 |    2 |
| 3 |    1 |
+---+------+
3 rows in set (0.00 sec)

replica> SELECT * FROM fc1;
+---+------+
| i | j    |
+---+------+
| 1 |    1 |
| 2 |    2 |
+---+------+
2 rows in set (0.00 sec)

replica> SELECT * FROM fc2;
+---+------+
| m | n    |
+---+------+
| 1 |    1 |
| 2 |    2 |
| 3 |    1 |
+---+------+
3 rows in set (0.00 sec)

现在假设您在源端执行以下DELETE语句:

source> DELETE FROM fc1 WHERE i=1;
Query OK, 1 row affected (0.09 sec)

由于级联,源端的fc2表现在只包含 1 行:

source> SELECT * FROM fc2;
+---+---+
| m | n |
+---+---+
| 2 | 2 |
+---+---+
1 row in set (0.00 sec)

然而,在副本上级联不会传播,因为在副本上对fc1DELETE不会从fc2中删除任何行。副本中的fc2的副本仍然包含最初插入的所有行:

replica> SELECT * FROM fc2;
+---+---+
| m | n |
+---+---+
| 1 | 1 |
| 3 | 1 |
| 2 | 2 |
+---+---+
3 rows in set (0.00 sec)

这种差异是由于级联删除是由InnoDB存储引擎内部处理的,这意味着没有任何更改被记录。

17.20 InnoDB memcached 插件

原文:dev.mysql.com/doc/refman/8.0/en/innodb-memcached.html

17.20.1 InnoDB memcached 插件的优势

17.20.2 InnoDB memcached 架构

17.20.3 设置 InnoDB memcached 插件

17.20.4 InnoDB memcached 多个 get 和范围查询支持

17.20.5 InnoDB memcached 插件的安全考虑

17.20.6 为 InnoDB memcached 插件编写应用程序

17.20.7 InnoDB memcached 插件和复制

17.20.8 InnoDB memcached 插件内部

17.20.9 InnoDB memcached 插件故障排除

重要提示

InnoDB memcached插件在 MySQL 8.3.0 中被移除,在 MySQL 8.0.22 中被弃用。

InnoDB memcached插件(daemon_memcached)提供了一个集成的memcached守护程序,自动从InnoDB表中存储和检索数据,将 MySQL 服务器转变为快速的“键-值存储”。您可以使用简单的getsetincr操作来代替在 SQL 中制定查询,避免与 SQL 解析和构建查询优化计划相关的性能开销。您也可以通过 SQL 访问相同的InnoDB表,以便进行方便、复杂的查询、批量操作和传统数据库软件的其他优势。

这种“NoSQL 风格”的接口使用memcached API 加速数据库操作,让InnoDB使用其缓冲池机制处理内存缓存。通过memcached操作修改的数据,如addsetincr,会存储到磁盘中的InnoDB表中。memcached的简单性与InnoDB的可靠性和一致性的结合,为用户提供了最佳的两全其美,如第 17.20.1 节“InnoDB memcached 插件的优势”中所解释的。有关架构概述,请参阅第 17.20.2 节“InnoDB memcached 架构”。

17.20.1 InnoDB memcached 插件的优势

原文:dev.mysql.com/doc/refman/8.0/en/innodb-memcached-benefits.html

本节概述了daemon_memcached插件的优势。InnoDB表和memcached的结合优于单独使用任一项。

  • 直接访问InnoDB存储引擎可以避免 SQL 的解析和规划开销。

  • memcached与 MySQL 服务器在同一进程空间中运行,避免了来回传递请求的网络开销。

  • 使用memcached协议写入的数据会透明地写入到InnoDB表中,而不经过 MySQL SQL 层。您可以控制写入的频率,以实现在更新非关键数据时获得更高的原始性能。

  • 通过memcached协议请求的数据会透明地从InnoDB表中查询,而不经过 MySQL SQL 层。

  • 对相同数据的后续请求是从InnoDB缓冲池中提供的。缓冲池处理内存中的缓存。您可以使用InnoDB配置选项调整数据密集型操作的性能。

  • 数据可以是非结构化或结构化的,取决于应用程序的类型。您可以为数据创建新表,或使用现有表。

  • InnoDB可以处理将多列值组合和分解为单个memcached项值,从而减少应用程序中所需的字符串解析和连接数量。例如,您可以将字符串值2|4|6|8存储在memcached缓存中,并让InnoDB根据分隔符字符拆分值,然后将结果存储在四个数值列中。

  • 内存和磁盘之间的传输是自动处理的,简化了应用程序逻辑。

  • 数据存储在 MySQL 数据库中,以防止崩溃、宕机和损坏。

  • 您可以通过 SQL 访问底层的InnoDB表进行报告、分析、临时查询、批量加载、多步事务计算、集合操作(如并集和交集)以及其他适合 SQL 表达力和灵活性的操作。

  • 通过在源服务器上结合使用daemon_memcached插件和 MySQL 复制,可以确保高可用性。

  • memcached与 MySQL 的集成提供了一种使内存中数据持久化的方式,因此您可以将其用于更重要的数据。您可以在应用程序中使用更多的addincr和类似的写操作,而不必担心数据丢失。您可以在不丢失缓存数据更新的情况下停止和启动memcached服务器。为防止意外宕机,您可以利用InnoDB的崩溃恢复、复制和备份功能。

  • InnoDB快速进行主键查找的方式非常适合memcached的单项查询。daemon_memcached插件使用的直接、低级别的数据库访问路径对于键-值查找比等效的 SQL 查询更有效率。

  • memcached的序列化功能可以将复杂数据结构、二进制文件甚至代码块转换为可存储的字符串,为将这些对象存入数据库提供了简单的方法。

  • 因为您可以通过 SQL 访问底层数据,所以可以生成报告、跨多个键进行搜索或更新,并在memcached数据上调用诸如AVG()MAX()之类的函数。所有这些操作在仅使用memcached时都是昂贵或复杂的。

  • 您不需要在启动时手动加载数据到memcached中。当应用程序请求特定键时,值会自动从数据库中检索,并使用InnoDB 缓冲池在内存中缓存。

  • 因为memcached消耗的 CPU 相对较少,其内存占用量易于控制,所以它可以轻松地与同一系统上的 MySQL 实例一起运行。

  • 因为数据一致性是由用于常规InnoDB表的机制强制执行的,所以您不必担心过时的memcached数据或在缺少键的情况下查询数据库的回退逻辑。

17.20.2 InnoDB memcached 架构

原文:dev.mysql.com/doc/refman/8.0/en/innodb-memcached-intro.html

InnoDB memcached插件将memcached实现为直接访问InnoDB存储引擎的 MySQL 插件守护程序,绕过 MySQL SQL 层。

以下图示说明了应用程序如何通过daemon_memcached插件访问数据,与 SQL 相比。

图 17.4 集成 memcached 服务器的 MySQL 服务器

显示应用程序使用 SQL 和 memcached 协议访问 InnoDB 存储引擎中的数据。使用 SQL,应用程序通过 MySQL 服务器和 Handler API 访问数据。使用 memcached 协议,应用程序绕过 MySQL 服务器,通过 memcached 插件和 InnoDB API 访问数据。memcached 插件由 innodb_memcache 接口和可选的本地缓存组成。

daemon_memcached插件的特点:

  • memcached作为mysqld的守护插件。mysqldmemcached在同一进程空间中运行,对数据具有非常低的延迟访问。

  • 直接访问InnoDB表,绕过 SQL 解析器、优化器,甚至 Handler API 层。

  • 标准的memcached协议,包括基于文本的协议和二进制协议。daemon_memcached插件通过了memcapable命令的所有 55 个兼容性测试。

  • 多列支持。您可以将多列映射到键值存储的“值”部分,列值由用户指定的分隔符字符分隔。

  • 默认情况下,使用memcached协议直接读写数据到InnoDB,让 MySQL 使用InnoDB缓冲池管理内存缓存。默认设置代表了高可靠性和数据库应用程序最少惊喜的组合。例如,默认设置避免了数据库端未提交数据,或者为memcachedget请求返回陈旧数据。

  • 高级用户可以将系统配置为传统的memcached服务器,所有数据仅缓存在memcached引擎(内存缓存)中,或者同时使用“memcached引擎”(内存缓存)和InnoDB memcached引擎(InnoDB作为后端持久存储)的组合。

  • 控制数据在InnoDBmemcached操作之间传递频率的配置选项包括innodb_api_bk_commit_intervaldaemon_memcached_r_batch_size,和daemon_memcached_w_batch_size。批量大小选项默认值为 1,以确保最大可靠性。

  • 通过daemon_memcached_option配置参数指定memcached选项的能力。例如,您可以更改memcached监听的端口,减少最大同时连接数,更改键值对的最大内存大小,或为错误日志启用调试消息。

  • innodb_api_trx_level配置选项控制由memcached处理的查询的事务隔离级别。虽然memcached没有事务的概念,但您可以使用此选项来控制memcached何时看到由daemon_memcached插件使用的表上发出的 SQL 语句引起的更改。默认情况下,innodb_api_trx_level设置为READ UNCOMMITTED

  • innodb_api_enable_mdl选项可用于在 MySQL 级别锁定表,以防止通过 SQL 接口对映射表进行 DDL 的删除或更改。如果没有锁定,表可以从 MySQL 层删除,但在memcached或其他用户停止使用之前,仍保留在InnoDB存储中。“MDL”代表“metadata locking”。

17.20.3 设置 InnoDB memcached 插件

原文:dev.mysql.com/doc/refman/8.0/en/innodb-memcached-setup.html

本节描述了如何在 MySQL 服务器上设置daemon_memcached插件。由于memcached守护程序与 MySQL 服务器紧密集成,以避免网络流量并最小化延迟,因此你需要在使用此功能的每个 MySQL 实例上执行此过程。

注意

在设置daemon_memcached插件之前,请参考 Section 17.20.5, “InnoDB memcached 插件的安全注意事项” 以了解所需的安全程序,以防止未经授权的访问。

先决条件

  • daemon_memcached插件仅支持 Linux、Solaris 和 macOS 平台。其他操作系统不受支持。

  • 在从源代码构建 MySQL 时,你必须使用 -DWITH_INNODB_MEMCACHED=ON 构建选项。此构建选项在 MySQL 插件目录(plugin_dir)中生成两个共享库,这些库是运行daemon_memcached插件所需的:

    • libmemcached.somemcached 守护程序插件到 MySQL。

    • innodb_engine.somemcachedInnoDB API 插件。

  • 必须安装libevent

    • 如果你没有从源代码构建 MySQL,那么libevent库不会包含在你的安装中。使用你的操作系统的安装方法来安装libevent 1.4.12 或更高版本。例如,根据操作系统的不同,你可能会使用apt-getyumport install。例如,在 Ubuntu Linux 上,使用:

      sudo apt-get install libevent-dev
      
    • 如果你从源代码发布中安装了 MySQL,libevent 1.4.12 已经捆绑在包中,并位于 MySQL 源代码目录的顶层。如果你使用捆绑版本的libevent,则无需采取任何操作。如果你想使用本地系统版本的libevent,你必须使用 -DWITH_LIBEVENT 构建选项设置为systemyes来构建 MySQL。

安装和配置 InnoDB memcached 插件

  1. 通过运行位于*MYSQL_HOME*/share中的innodb_memcached_config.sql配置脚本,配置daemon_memcached插件以与InnoDB表交互。此脚本安装了包含三个必需表(cache_policiesconfig_optionscontainers)的innodb_memcache数据库。它还在test数据库中安装了demo_test示例表。

    mysql> source *MYSQL_HOME*/share/innodb_memcached_config.sql
    

    运行innodb_memcached_config.sql脚本是一次性操作。如果以后卸载并重新安装daemon_memcached插件,表将保留在原位。

    mysql> USE innodb_memcache;
    mysql> SHOW TABLES;
    +---------------------------+
    | Tables_in_innodb_memcache |
    +---------------------------+
    | cache_policies            |
    | config_options            |
    | containers                |
    +---------------------------+
    
    mysql> USE test;
    mysql> SHOW TABLES;
    +----------------+
    | Tables_in_test |
    +----------------+
    | demo_test      |
    +----------------+
    

    在这些表中,innodb_memcache.containers 表最重要。containers 表中的条目提供到 InnoDB 表列的映射。每个使用 daemon_memcached 插件的 InnoDB 表都需要在 containers 表中有一个条目。

    innodb_memcached_config.sql 脚本在 containers 表中插入一个条目,为 demo_test 表提供映射。它还在 demo_test 表中插入一行数据。这些数据允许你在设置完成后立即验证安装。

    mysql> SELECT * FROM innodb_memcache.containers\G
    *************************** 1\. row ***************************
                      name: aaa
                 db_schema: test
                  db_table: demo_test
               key_columns: c1
             value_columns: c2
                     flags: c3
                cas_column: c4
        expire_time_column: c5
    unique_idx_name_on_key: PRIMARY 
    mysql> SELECT * FROM test.demo_test;
    +----+------------------+------+------+------+
    | c1 | c2               | c3   | c4   | c5   |
    +----+------------------+------+------+------+
    | AA | HELLO, HELLO     |    8 |    0 |    0 |
    +----+------------------+------+------+------+
    

    有关 innodb_memcache 表和 demo_test 示例表的更多信息,请参见 第 17.20.8 节,“InnoDB memcached 插件内部”。

  2. 通过运行 INSTALL PLUGIN 语句激活 daemon_memcached 插件:

    mysql> INSTALL PLUGIN daemon_memcached soname "libmemcached.so";
    

    一旦插件安装完成,每次 MySQL 服务器重新启动时都会自动激活。

验证 InnoDB 和 memcached 设置

要验证 daemon_memcached 插件设置,使用 telnet 会话发出 memcached 命令。默认情况下,memcached 守护程序监听端口 11211。

  1. test.demo_test 表中检索数据。demo_test 表中的单行数据具有键值 AA

    telnet localhost 11211
    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'.
    get AA
    VALUE AA 8 12
    HELLO, HELLO
    END
    
  2. 使用 set 命令插入数据。

    set BB 10 0 16
    GOODBYE, GOODBYE
    STORED
    

    其中:

    • set 是存储值的命令

    • BB 是键

    • 10 是操作的标志;memcached 忽略但客户端可能用于指示任何类型的信息;如果未使用,请指定 0

    • 0 是过期时间(TTL);如果未使用,请指定 0

    • 提供的值块的长度为 16 字节

    • GOODBYE, GOODBYE 是存储的值

  3. 通过连接到 MySQL 服务器并查询 test.demo_test 表来验证插入的数据是否存储在 MySQL 中。

    mysql> SELECT * FROM test.demo_test;
    +----+------------------+------+------+------+
    | c1 | c2               | c3   | c4   | c5   |
    +----+------------------+------+------+------+
    | AA | HELLO, HELLO     |    8 |    0 |    0 |
    | BB | GOODBYE, GOODBYE |   10 |    1 |    0 |
    +----+------------------+------+------+------+
    
  4. 返回 telnet 会话并使用键 BB 检索之前插入的数据。

    get BB
    VALUE BB 10 16
    GOODBYE, GOODBYE
    END
    quit
    

如果关闭 MySQL 服务器,也会关闭集成的 memcached 服务器,进一步尝试访问 memcached 数据会因连接错误而失败。通常情况下,此时 memcached 数据也会消失,当 memcached 重新启动时,你需要应用逻辑来重新加载数据。然而,InnoDB memcached 插件会自动化这个过程。

当你重新启动 MySQL 时,get 操作会再次返回你在之前 memcached 会话中存储的键值对。当请求一个键并且相关值不在内存缓存中时,该值会自动从 MySQL test.demo_test 表中查询。

创建新表和列映射

此示例展示了如何使用 daemon_memcached 插件设置自己的 InnoDB 表。

  1. 创建一个InnoDB表。表必须具有具有唯一索引的键列。城市表的键列是city_id,定义为主键。表还必须包括用于flagscasexpiry值的列。可能有一个或多个值列。city表有三个值列(namestatecountry)。

    注意

    列名没有特殊要求,只要向innodb_memcache.containers表添加有效映射即可。

    mysql> CREATE TABLE city (
           city_id VARCHAR(32),
           name VARCHAR(1024),
           state VARCHAR(1024),
           country VARCHAR(1024),
           flags INT,
           cas BIGINT UNSIGNED, 
           expiry INT,
           primary key(city_id)
           ) ENGINE=InnoDB;
    
  2. innodb_memcache.containers表添加一个条目,以便daemon_memcached插件知道如何访问InnoDB表。该条目必须满足innodb_memcache.containers表的定义。有关每个字段的描述,请参见第 17.20.8 节,“InnoDB memcached 插件内部”。

    mysql> DESCRIBE innodb_memcache.containers;
    +------------------------+--------------+------+-----+---------+-------+
    | Field                  | Type         | Null | Key | Default | Extra |
    +------------------------+--------------+------+-----+---------+-------+
    | name                   | varchar(50)  | NO   | PRI | NULL    |       |
    | db_schema              | varchar(250) | NO   |     | NULL    |       |
    | db_table               | varchar(250) | NO   |     | NULL    |       |
    | key_columns            | varchar(250) | NO   |     | NULL    |       |
    | value_columns          | varchar(250) | YES  |     | NULL    |       |
    | flags                  | varchar(250) | NO   |     | 0       |       |
    | cas_column             | varchar(250) | YES  |     | NULL    |       |
    | expire_time_column     | varchar(250) | YES  |     | NULL    |       |
    | unique_idx_name_on_key | varchar(250) | NO   |     | NULL    |       |
    +------------------------+--------------+------+-----+---------+-------+
    

    城市表的innodb_memcache.containers表条目定义为:

    mysql> INSERT INTO `innodb_memcache`.`containers` (
           `name`, `db_schema`, `db_table`, `key_columns`, `value_columns`,
           `flags`, `cas_column`, `expire_time_column`, `unique_idx_name_on_key`)
           VALUES ('default', 'test', 'city', 'city_id', 'name|state|country', 
           'flags','cas','expiry','PRIMARY');
    
    • containers.name列指定default,以将city表配置为与daemon_memcached插件一起使用的默认InnoDB表。

    • 多个InnoDB表列(namestatecountry)使用“|”分隔符映射到containers.value_columns

    • innodb_memcache.containers表的flagscas_columnexpire_time_column字段在使用daemon_memcached插件的应用程序中通常不重要。但是,每个字段都需要指定一个指定的InnoDB表列。在插入数据时,如果未使用这些列,请为这些列指定0

  3. 更新innodb_memcache.containers表后,重新启动daemon_memcache插件以应用更改。

    mysql> UNINSTALL PLUGIN daemon_memcached;
    
    mysql> INSTALL PLUGIN daemon_memcached soname "libmemcached.so";
    
  4. 使用 telnet,使用memcachedset命令向city表插入数据。

    telnet localhost 11211
    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'.
    set B 0 0 22
    BANGALORE|BANGALORE|IN
    STORED
    
  5. 使用 MySQL,查询test.city表以验证您插入的数据是否已存储。

    mysql> SELECT * FROM test.city;
    +---------+-----------+-----------+---------+-------+------+--------+
    | city_id | name      | state     | country | flags | cas  | expiry |
    +---------+-----------+-----------+---------+-------+------+--------+
    | B       | BANGALORE | BANGALORE | IN      |     0 |    3 |      0 |
    +---------+-----------+-----------+---------+-------+------+--------+
    
  6. 使用 MySQL,向test.city表插入额外数据。

    mysql> INSERT INTO city VALUES ('C','CHENNAI','TAMIL NADU','IN', 0, 0 ,0);
    mysql> INSERT INTO city VALUES ('D','DELHI','DELHI','IN', 0, 0, 0);
    mysql> INSERT INTO city VALUES ('H','HYDERABAD','TELANGANA','IN', 0, 0, 0);
    mysql> INSERT INTO city VALUES ('M','MUMBAI','MAHARASHTRA','IN', 0, 0, 0);
    

    注意

    如果未使用,建议为flagscas_columnexpire_time_column字段指定值0

  7. 使用 telnet,发出memcachedget命令以检索使用 MySQL 插入的数据。

    get H
    VALUE H 0 22
    HYDERABAD|TELANGANA|IN
    END
    

配置 InnoDB memcached 插件

传统的memcached配置选项可以在 MySQL 配置文件或者mysqld启动字符串中指定,编码在daemon_memcached_option配置参数的参数中。memcached配置选项在插件加载时生效,这发生在每次启动 MySQL 服务器时。

例如,要使memcached监听端口 11222 而不是默认端口 11211,请将-p11222指定为daemon_memcached_option配置选项的参数:

mysqld .... --daemon_memcached_option="-p11222"

其他memcached选项可以编码在daemon_memcached_option字符串中。例如,您可以指定选项来减少最大同时连接数,更改键值对的最大内存大小,或者启用错误日志的调试消息等。

也有一些特定于daemon_memcached插件的配置选项。这些包括:

  • daemon_memcached_engine_lib_name:指定实现InnoDB memcached插件的共享库。默认设置为innodb_engine.so

  • daemon_memcached_engine_lib_path:包含实现InnoDB memcached插件的共享库的目录路径。默认值为 NULL,表示插件目录。

  • daemon_memcached_r_batch_size:定义读操作(get)的批量提交大小。它指定在进行多少次memcached读取操作后发生提交。daemon_memcached_r_batch_size默认设置为 1,以便每个get请求访问InnoDB表中最近提交的数据,无论数据是通过memcached还是通过 SQL 更新的。当值大于 1 时,每次get调用都会增加读操作计数器。flush_all调用会重置读取和写入计数器。

  • daemon_memcached_w_batch_size:定义写操作(setreplaceappendprependincrdecr等)的批量提交大小。daemon_memcached_w_batch_size默认设置为 1,以防止在停机情况下丢失未提交的数据,并且使底层表上的 SQL 查询访问最新数据。当值大于 1 时,每次addsetincrdecrdelete调用都会增加写操作计数器。flush_all调用会重置读取和写入计数器。

默认情况下,您不需要修改daemon_memcached_engine_lib_namedaemon_memcached_engine_lib_path。例如,如果您想要使用不同的存储引擎来memcached(如 NDB memcached引擎),则可以配置这些选项。

daemon_memcached插件配置参数可以在 MySQL 配置文件中或在mysqld启动字符串中指定。它们在加载daemon_memcached插件时生效。

在对daemon_memcached插件配置进行更改时,重新加载插件以应用更改。要这样做,请发出以下语句:

mysql> UNINSTALL PLUGIN daemon_memcached;

mysql> INSTALL PLUGIN daemon_memcached soname "libmemcached.so";

插件重新启动时会保留配置设置、所需表格和数据。

有关启用和禁用插件的更多信息,请参见第 7.6.1 节,“安装和卸载插件”。

17.20.4 InnoDB memcached 多个获取和范围查询支持

原文:dev.mysql.com/doc/refman/8.0/en/innodb-memcached-multiple-get-range-query.html

daemon_memcached插件支持多个获取操作(在单个memcached查询中获取多个键值对)和范围查询。

多个获取操作

在单个memcached查询中获取多个键值对的能力通过减少客户端和服务器之间的通信流量来提高读取性能。对于InnoDB,这意味着更少的事务和打开表操作。

以下示例演示了多个获取支持。该示例使用了创建新表和列映射中描述的test.city表。

mysql> USE test;
mysql> SELECT * FROM test.city;
+---------+-----------+-------------+---------+-------+------+--------+
| city_id | name      | state       | country | flags | cas  | expiry |
+---------+-----------+-------------+---------+-------+------+--------+
| B       | BANGALORE | BANGALORE   | IN      |     0 |    1 |      0 |
| C       | CHENNAI   | TAMIL NADU  | IN      |     0 |    0 |      0 |
| D       | DELHI     | DELHI       | IN      |     0 |    0 |      0 |
| H       | HYDERABAD | TELANGANA   | IN      |     0 |    0 |      0 |
| M       | MUMBAI    | MAHARASHTRA | IN      |     0 |    0 |      0 |
+---------+-----------+-------------+---------+-------+------+--------+

运行get命令以从city表中检索所有值。结果以键值对序列返回。

telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
get B C D H M
VALUE B 0 22
BANGALORE|BANGALORE|IN
VALUE C 0 21
CHENNAI|TAMIL NADU|IN
VALUE D 0 14
DELHI|DELHI|IN
VALUE H 0 22
HYDERABAD|TELANGANA|IN
VALUE M 0 21
MUMBAI|MAHARASHTRA|IN
END

在单个get命令中检索多个值时,您可以切换表(使用@@*containers.name*符号)以检索第一个键的值,但不能为后续键切换表。例如,此示例中的表切换是有效的:

get @@aaa.AA BB
VALUE @@aaa.AA 8 12
HELLO, HELLO
VALUE BB 10 16
GOODBYE, GOODBYE
END

尝试在同一个get命令中再次切换表以从不同表中检索键值不受支持。

通过多个获取操作检索的键的数量没有限制,但存储结果的内存限制为 128MB。

范围查询

对于范围查询,daemon_memcached插件支持以下比较运算符:<><=>=。运算符前必须加上@符号。当范围查询找到多个匹配的键值对时,结果以键值对序列返回。

以下示例演示了范围查询支持。这些示例使用了创建新表和列映射中描述的test.city表。

mysql> SELECT * FROM test.city;
+---------+-----------+-------------+---------+-------+------+--------+
| city_id | name      | state       | country | flags | cas  | expiry |
+---------+-----------+-------------+---------+-------+------+--------+
| B       | BANGALORE | BANGALORE   | IN      |     0 |    1 |      0 |
| C       | CHENNAI   | TAMIL NADU  | IN      |     0 |    0 |      0 |
| D       | DELHI     | DELHI       | IN      |     0 |    0 |      0 |
| H       | HYDERABAD | TELANGANA   | IN      |     0 |    0 |      0 |
| M       | MUMBAI    | MAHARASHTRA | IN      |     0 |    0 |      0 |
+---------+-----------+-------------+---------+-------+------+--------+

打开 telnet 会话:

telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.

要获取所有大于B的值,请输入get @>B

get @>B
VALUE C 0 21
CHENNAI|TAMIL NADU|IN
VALUE D 0 14
DELHI|DELHI|IN
VALUE H 0 22
HYDERABAD|TELANGANA|IN
VALUE M 0 21
MUMBAI|MAHARASHTRA|IN
END

要获取所有小于M的值,请输入get @<M

get @<M
VALUE B 0 22
BANGALORE|BANGALORE|IN
VALUE C 0 21
CHENNAI|TAMIL NADU|IN
VALUE D 0 14
DELHI|DELHI|IN
VALUE H 0 22
HYDERABAD|TELANGANA|IN
END

要获取所有小于或等于M的值,请输入get @<=M

get @<=M
VALUE B 0 22
BANGALORE|BANGALORE|IN
VALUE C 0 21
CHENNAI|TAMIL NADU|IN
VALUE D 0 14
DELHI|DELHI|IN
VALUE H 0 22
HYDERABAD|TELANGANA|IN
VALUE M 0 21
MUMBAI|MAHARASHTRA|IN

要获取大于B但小于M的值,请输入get @>B@<M

get @>B@<M
VALUE C 0 21
CHENNAI|TAMIL NADU|IN
VALUE D 0 14
DELHI|DELHI|IN
VALUE H 0 22
HYDERABAD|TELANGANA|IN
END

最多可以解析两个比较运算符,一个是'小于'(@<)或'小于或等于'(@<=)运算符,另一个是'大于'(@>)或'大于或等于'(@>=)运算符。任何额外的运算符都被视为键的一部分。例如,如果您发出带有三个运算符的get命令,则第三个运算符(@>C)被视为键的一部分,get命令将搜索小于M且大于B@>C的值。

get @<M@>B@>C
VALUE C 0 21
CHENNAI|TAMIL NADU|IN
VALUE D 0 14
DELHI|DELHI|IN
VALUE H 0 22
HYDERABAD|TELANGANA|IN

17.20.5 InnoDB memcached 插件的安全注意事项

原文:dev.mysql.com/doc/refman/8.0/en/innodb-memcached-security.html

注意

在将daemon_memcached插件部署到生产服务器之前,请参考本节,甚至在包含敏感数据的 MySQL 实例上的测试服务器上。

因为memcached默认不使用身份验证机制,而可选的 SASL 身份验证不如传统的 DBMS 安全措施强大,因此只在使用daemon_memcached插件的 MySQL 实例中保留非敏感数据,并将使用此配置的任何服务器与潜在入侵者隔离开。不要允许来自 Internet 的memcached访问这些服务器;只允许来自受防火墙保护的内部网络的访问,最好是来自可以限制成员资格的子网。

通过使用 SASL 对 memcached 进行密码保护

SASL 支持提供了保护 MySQL 数据库免受通过memcached客户端的未经身份验证访问的能力。本节介绍如何启用具有daemon_memcached插件的 SASL。这些步骤几乎与为传统memcached服务器启用 SASL 执行的步骤相同。

SASL 代表“简单身份验证和安全层”,这是一种为基于连接的协议添加身份验证支持的标准。memcached在 1.4.3 版本中添加了 SASL 支持。

SASL 身份验证仅受二进制协议支持。

memcached客户端只能访问在innodb_memcache.containers表中注册的InnoDB表。尽管 DBA 可以对这些表施加访问限制,但无法控制通过memcached应用程序的访问。因此,提供了 SASL 支持以控制与daemon_memcached插件关联的InnoDB表的访问。

以下部分显示了如何构建、启用和测试启用 SASL 的daemon_memcached插件。

构建和启用具有 InnoDB memcached 插件的 SASL

默认情况下,MySQL 发布包中不包含启用 SASL 的daemon_memcached插件,因为启用 SASL 的daemon_memcached插件需要使用 SASL 库构建memcached。要启用 SASL 支持,请下载 MySQL 源代码,并在下载 SASL 库后重新构建daemon_memcached插件:

  1. 安装 SASL 开发和实用程序库。例如,在 Ubuntu 上,使用apt-get获取这些库:

    sudo apt-get -f install libsasl2-2 sasl2-bin libsasl2-2 libsasl2-dev libsasl2-modules
    
  2. 通过将ENABLE_MEMCACHED_SASL=1添加到cmake选项中,可以构建具有 SASL 功能的daemon_memcached插件共享库。memcached还提供简单的明文密码支持,这有助于测试。要启用简单的明文密码支持,请指定ENABLE_MEMCACHED_SASL_PWDB=1 cmake选项。

    总之,添加以下三个cmake选项:

    cmake ... -DWITH_INNODB_MEMCACHED=1 -DENABLE_MEMCACHED_SASL=1 -DENABLE_MEMCACHED_SASL_PWDB=1
    
  3. 安装daemon_memcached插件,如第 17.20.3 节,“设置 InnoDB memcached 插件”所述。

  4. 配置一个用户名和密码文件。(此示例使用memcached简单明文密码支持。)

    1. 在文件中创建一个名为testname的用户,并将密码定义为testpasswd

      echo "testname:testpasswd:::::::" >/home/jy/memcached-sasl-db
      
    2. 配置MEMCACHED_SASL_PWDB环境变量,通知memcached用户名称和密码文件的位置:

      export MEMCACHED_SASL_PWDB=/home/jy/memcached-sasl-db
      
    3. 通知memcached使用明文密码:

      echo "mech_list: plain" > /home/jy/work2/msasl/clients/memcached.conf
      export SASL_CONF_PATH=/home/jy/work2/msasl/clients
      
  5. 通过在daemon_memcached_option配置参数中编码memcached -S选项,通过重新启动 MySQL 服务器启用 SASL:

    mysqld ... --daemon_memcached_option="-S"
    
  6. 为了测试设置,使用支持 SASL 的客户端,如SASL-enabled libmemcached

    memcp --servers=localhost:11211 --binary  --username=testname
      --password=*password* myfile.txt
    
    memcat --servers=localhost:11211 --binary --username=testname
      --password=*password* myfile.txt
    

    如果指定了不正确的用户名或密码,则操作将被拒绝,并显示memcache error AUTHENTICATION FAILURE消息。在这种情况下,请检查memcached-sasl-db文件中设置的明文密码,以验证您提供的凭据是否正确。

还有其他测试使用memcached进行 SASL 身份验证的方法,但上述描述的方法是最直接的。

17.20.6 为 InnoDB memcached 插件编写应用程序

原文:dev.mysql.com/doc/refman/8.0/en/innodb-memcached-developing.html

17.20.6.1 为 InnoDB memcached 插件调整现有 MySQL 模式

17.20.6.2 为 InnoDB memcached 插件调整 memcached 应用程序

17.20.6.3 调整 InnoDB memcached 插件性能

17.20.6.4 控制 InnoDB memcached 插件的事务行为

17.20.6.5 将 DML 语句调整为 memcached 操作

17.20.6.6 在底层 InnoDB 表上执行 DML 和 DDL 语句

通常,为InnoDB memcached插件编写应用程序涉及对使用 MySQL 或memcached API 的现有代码进行一定程度的重写或调整。

  • 使用daemon_memcached插件,你不再需要在低性能机器上运行许多传统的memcached服务器,而是将与 MySQL 服务器数量相同的memcached服务器运行在具有大量磁盘存储和内存的相对高性能机器上。你可能会重用一些与memcached API 一起工作的现有代码,但由于不同的服务器配置,可能需要进行适应。

  • 通过daemon_memcached插件存储的数据存储在VARCHARTEXTBLOB列中,并且必须转换为执行数值操作。你可以在应用程序端执行转换,或者在查询中使用CAST()函数执行转换。

  • 如果你来自数据库背景,你可能习惯于具有许多列的通用 SQL 表。memcached代码访问的表可能只有几列,甚至只有一个列用于保存数据值。

  • 你可能需要调整应用程序的部分部分,以执行单行查询、插入、更新或删除操作,以提高代码关键部分的性能。通过InnoDB memcached接口执行的查询(读取)和 DML(写入)操作在性能上可以显著提高。写入操作的性能改进通常大于读取操作的性能改进,因此你可能需要专注于调整记录日志或记录网站上交互选择的代码。

以下部分将更详细地探讨这些要点。

原文:dev.mysql.com/doc/refman/8.0/en/innodb-memcached-porting-mysql.html

17.20.6.1 调整现有的 MySQL 模式以适应 InnoDB memcached 插件

在调整现有的 MySQL 模式或应用程序以使用daemon_memcached插件时,请考虑这些memcached应用程序的方面:

  • memcached 键不能包含空格或换行符,因为这些字符在 ASCII 协议中用作分隔符。如果您使用包含空格的查找值,请在将其用作add()set()get()等调用中的键之前将其转换或哈希为无空格的值。尽管在使用二进制协议的程序中理论上允许这些字符作为键,但为了确保与广泛范围的客户端兼容性,您应限制键中使用的字符。

  • 如果在InnoDB表中有一个短的数字主键列,请将其转换为字符串值,以将其用作memcached的唯一查找键。如果memcached服务器用于多个应用程序,或与多个InnoDB表一起使用,请考虑修改名称以确保其唯一性。例如,在数字值之前添加表名,或数据库名和表名。

    注意

    daemon_memcached插件支持在具有INTEGER定义为主键的映射InnoDB表上进行插入和读取。

  • 不能使用分区表来查询或存储使用memcached的数据。

  • memcached 协议将数字值作为字符串传递。为了在底层的InnoDB表中存储数字值,实现可以用于 SQL 函数如SUM()AVG()的计数器,例如:

    • 使用足够字符的VARCHAR列来容纳预期最大数字的所有数字(如果适用,还有负号、小数点或两者的其他字符)。

    • 在执行使用列值进行算术运算的任何查询中,使用CAST()函数将值从字符串转换为整数,或转换为其他数值类型。例如:

      # Alphabetic entries are returned as zero.
      
      SELECT CAST(c2 as unsigned integer) FROM demo_test;
      
      # Since there could be numeric values of 0, can't disqualify them.
      # Test the string values to find the ones that are integers, and average only those.
      
      SELECT AVG(cast(c2 as unsigned integer)) FROM demo_test
        WHERE c2 BETWEEN '0' and '9999999999';
      
      # Views let you hide the complexity of queries. The results are already converted;
      # no need to repeat conversion functions and WHERE clauses each time.
      
      CREATE VIEW numbers AS SELECT c1 KEY, CAST(c2 AS UNSIGNED INTEGER) val
        FROM demo_test WHERE c2 BETWEEN '0' and '9999999999';
      SELECT SUM(val) FROM numbers;
      

      注意

      结果集中的任何字母值在调用CAST()时都会转换为 0。在使用诸如AVG()之类依赖于结果集中的行数的函数时,包括WHERE子句以过滤非数字值。

  • 如果用作键的InnoDB列可能具有超过 250 字节的值,请将该值哈希为少于 250 字节。

  • 要在daemon_memcached插件中使用现有表,需在innodb_memcache.containers表中为其定义一个条目。要使该表成为所有memcached请求的默认表,需在name列中指定一个值为default,然后重新启动 MySQL 服务器以使更改生效。如果您为不同类别的memcached数据使用多个表,请在innodb_memcache.containers表中设置多个条目,其中name值由您选择,然后在应用程序中发出形式为get @@*name*set @@*name*memcached请求,以指定用于后续memcached请求的表。

    要查看使用预定义的test.demo_test表之外的表的示例,请参阅示例 17.13,“使用自己的表与 InnoDB memcached 应用程序”。有关所需表布局,请参阅第 17.20.8 节,“InnoDB memcached 插件内部”。

  • 要使用多个InnoDB表列值与memcached键值对,需在innodb_memcache.containers条目的value_columns字段中指定以逗号、分号、空格或竖线字符分隔的列名。例如,在value_columns字段中指定col1,col2,col3col1|col2|col3

    在将字符串传递给memcachedaddset调用之前,使用竖线字符作为分隔符将列值连接成单个字符串。字符串会自动解包为正确的列。每个get调用返回一个包含以竖线字符分隔的列值的单个字符串。您可以使用适当的应用程序语法解包这些值。

示例 17.13 使用自己的表与 InnoDB memcached 应用程序

该示例展示了如何使用自己的表与一个使用memcached进行数据操作的示例 Python 应用程序。

该示例假定daemon_memcached插件已按照第 17.20.3 节,“设置 InnoDB memcached 插件”中描述的方式安装。还假定您的系统已配置为运行使用python-memcache模块的 Python 脚本。

  1. 创建multicol表,其中存储包括人口、面积和驾驶侧数据(右侧为'R',左侧为'L')的国家信息。

    mysql> USE test;
    
    mysql> CREATE TABLE `multicol` (
            `country` varchar(128) NOT NULL DEFAULT '',
            `population` varchar(10) DEFAULT NULL,
            `area_sq_km` varchar(9) DEFAULT NULL,
            `drive_side` varchar(1) DEFAULT NULL,
            `c3` int(11) DEFAULT NULL,
            `c4` bigint(20) unsigned DEFAULT NULL,
            `c5` int(11) DEFAULT NULL,
            PRIMARY KEY (`country`)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    
  2. 将记录插入innodb_memcache.containers表中,以便daemon_memcached插件可以访问multicol表。

    mysql> INSERT INTO innodb_memcache.containers
           (name,db_schema,db_table,key_columns,value_columns,flags,cas_column,
           expire_time_column,unique_idx_name_on_key)
           VALUES
           ('bbb','test','multicol','country','population,area_sq_km,drive_side',
           'c3','c4','c5','PRIMARY');
    
    mysql> COMMIT;
    
    • innodb_memcache.containers记录中的multicol表指定了一个name值为'bbb',这是表标识符。

      注意

      如果单个InnoDB表用于所有memcached应用程序,则可以将name值设置为default,以避免使用@@符号切换表。

    • db_schema列设置为test,这是multicol表所在的数据库的名称。

    • db_table列设置为multicol,这是InnoDB表的名称。

    • key_columns设置为唯一的country列。country列在multicol表定义中被定义为主键。

    • 不是使用单个InnoDB表列来保存复合数据值,数据分布在三个表列(populationarea_sq_kmdrive_side)之间。为了容纳多个值列,value_columns字段中指定了一个逗号分隔的列列表。在存储或检索值时,value_columns字段中定义的列将被使用。

    • flagsexpire_timecas_column字段的值基于demo.test示例表中使用的值。在使用daemon_memcached插件的应用程序中,这些字段通常不重要,因为 MySQL 会保持数据同步,不需要担心数据过期或变得陈旧。

    • unique_idx_name_on_key字段设置为PRIMARY,指的是在multicol表中唯一的country列上定义的主索引。

  3. 将示例 Python 应用程序复制到一个文件中。在本例中,示例脚本被复制到一个名为multicol.py的文件中。

    示例 Python 应用程序将数据插入multicol表,并检索所有键的数据,演示如何通过daemon_memcached插件访问InnoDB表。

    import sys, os
    import memcache
    
    def connect_to_memcached():
      memc = memcache.Client(['127.0.0.1:11211'], debug=0);
      print "Connected to memcached."
      return memc
    
    def banner(message):
      print
      print "=" * len(message)
      print message
      print "=" * len(message)
    
    country_data = [
    ("Canada","34820000","9984670","R"),
    ("USA","314242000","9826675","R"),
    ("Ireland","6399152","84421","L"),
    ("UK","62262000","243610","L"),
    ("Mexico","113910608","1972550","R"),
    ("Denmark","5543453","43094","R"),
    ("Norway","5002942","385252","R"),
    ("UAE","8264070","83600","R"),
    ("India","1210193422","3287263","L"),
    ("China","1347350000","9640821","R"),
    ]
    
    def switch_table(memc,table):
      key = "@@" + table
      print "Switching default table to '" + table + "' by issuing GET for '" + key + "'."
      result = memc.get(key)
    
    def insert_country_data(memc):
      banner("Inserting initial data via memcached interface")
      for item in country_data:
        country = item[0]
        population = item[1]
        area = item[2]
        drive_side = item[3]
    
        key = country
        value = "|".join([population,area,drive_side])
        print "Key = " + key
        print "Value = " + value
    
        if memc.add(key,value):
          print "Added new key, value pair."
        else:
          print "Updating value for existing key."
          memc.set(key,value)
    
    def query_country_data(memc):
      banner("Retrieving data for all keys (country names)")
      for item in country_data:
        key = item[0]
        result = memc.get(key)
        print "Here is the result retrieved from the database for key " + key + ":"
        print result
        (m_population, m_area, m_drive_side) = result.split("|")
        print "Unpacked population value: " + m_population
        print "Unpacked area value      : " + m_area
        print "Unpacked drive side value: " + m_drive_side
    
    if __name__ == '__main__':
    
      memc = connect_to_memcached()
      switch_table(memc,"bbb")
      insert_country_data(memc)
      query_country_data(memc)
    
      sys.exit(0)
    

    示例 Python 应用程序注意事项:

    • 运行应用程序不需要数据库授权,因为数据操作是通过memcached接口执行的。唯一需要的信息是memcached守护程序在本地系统上监听的端口号。

    • 为确保应用程序使用multicol表,调用switch_table()函数,该函数使用@@符号执行虚拟的getset请求。请求中的name值为bbb,这是在innodb_memcache.containers.name字段中定义的multicol表标识符。

      在实际应用程序中可能会使用更具描述性的name值。这个例子只是说明了在get @@...请求中指定了一个表标识符,而不是表名。

    • 用于插入和查询数据的实用函数演示了如何将 Python 数据结构转换为用于通过addset请求将数据发送到 MySQL 的管道分隔值,以及如何解压get请求返回的管道分隔值。只有在将单个memcached值映射到多个 MySQL 表列时才需要进行这种额外处理。

  4. 运行示例 Python 应用程序。

    $> python multicol.py
    

    如果成功,示例应用程序将返回以下输出:

    Connected to memcached.
    Switching default table to 'bbb' by issuing GET for '@@bbb'.
    
    ==============================================
    Inserting initial data via memcached interface
    ==============================================
    Key = Canada
    Value = 34820000|9984670|R
    Added new key, value pair.
    Key = USA
    Value = 314242000|9826675|R
    Added new key, value pair.
    Key = Ireland
    Value = 6399152|84421|L
    Added new key, value pair.
    Key = UK
    Value = 62262000|243610|L
    Added new key, value pair.
    Key = Mexico
    Value = 113910608|1972550|R
    Added new key, value pair.
    Key = Denmark
    Value = 5543453|43094|R
    Added new key, value pair.
    Key = Norway
    Value = 5002942|385252|R
    Added new key, value pair.
    Key = UAE
    Value = 8264070|83600|R
    Added new key, value pair.
    Key = India
    Value = 1210193422|3287263|L
    Added new key, value pair.
    Key = China
    Value = 1347350000|9640821|R
    Added new key, value pair.
    
    ============================================
    Retrieving data for all keys (country names)
    ============================================
    Here is the result retrieved from the database for key Canada:
    34820000|9984670|R
    Unpacked population value: 34820000
    Unpacked area value      : 9984670
    Unpacked drive side value: R
    Here is the result retrieved from the database for key USA:
    314242000|9826675|R
    Unpacked population value: 314242000
    Unpacked area value      : 9826675
    Unpacked drive side value: R
    Here is the result retrieved from the database for key Ireland:
    6399152|84421|L
    Unpacked population value: 6399152
    Unpacked area value      : 84421
    Unpacked drive side value: L
    Here is the result retrieved from the database for key UK:
    62262000|243610|L
    Unpacked population value: 62262000
    Unpacked area value      : 243610
    Unpacked drive side value: L
    Here is the result retrieved from the database for key Mexico:
    113910608|1972550|R
    Unpacked population value: 113910608
    Unpacked area value      : 1972550
    Unpacked drive side value: R
    Here is the result retrieved from the database for key Denmark:
    5543453|43094|R
    Unpacked population value: 5543453
    Unpacked area value      : 43094
    Unpacked drive side value: R
    Here is the result retrieved from the database for key Norway:
    5002942|385252|R
    Unpacked population value: 5002942
    Unpacked area value      : 385252
    Unpacked drive side value: R
    Here is the result retrieved from the database for key UAE:
    8264070|83600|R
    Unpacked population value: 8264070
    Unpacked area value      : 83600
    Unpacked drive side value: R
    Here is the result retrieved from the database for key India:
    1210193422|3287263|L
    Unpacked population value: 1210193422
    Unpacked area value      : 3287263
    Unpacked drive side value: L
    Here is the result retrieved from the database for key China:
    1347350000|9640821|R
    Unpacked population value: 1347350000
    Unpacked area value      : 9640821
    Unpacked drive side value: R
    
  5. 查询innodb_memcache.containers表以查看您之前为multicol表插入的记录。第一条记录是在初始daemon_memcached插件设置期间创建的demo_test表的示例条目。第二条记录是您为multicol表插入的条目。

    mysql> SELECT * FROM innodb_memcache.containers\G
    *************************** 1\. row ***************************
                      name: aaa
                 db_schema: test
                  db_table: demo_test
               key_columns: c1
             value_columns: c2
                     flags: c3
                cas_column: c4
        expire_time_column: c5
    unique_idx_name_on_key: PRIMARY
    *************************** 2\. row ***************************
                      name: bbb
                 db_schema: test
                  db_table: multicol
               key_columns: country
             value_columns: population,area_sq_km,drive_side
                     flags: c3
                cas_column: c4
        expire_time_column: c5
    unique_idx_name_on_key: PRIMARY
    
  6. 查询multicol表以查看样本 Python 应用程序插入的数据。这些数据可供 MySQL 查询,演示了如何使用 SQL 或通过应用程序(使用适当的 MySQL 连接器或 API)访问相同的数据。

    mysql> SELECT * FROM test.multicol;
    +---------+------------+------------+------------+------+------+------+
    | country | population | area_sq_km | drive_side | c3   | c4   | c5   |
    +---------+------------+------------+------------+------+------+------+
    | Canada  | 34820000   | 9984670    | R          |    0 |   11 |    0 |
    | China   | 1347350000 | 9640821    | R          |    0 |   20 |    0 |
    | Denmark | 5543453    | 43094      | R          |    0 |   16 |    0 |
    | India   | 1210193422 | 3287263    | L          |    0 |   19 |    0 |
    | Ireland | 6399152    | 84421      | L          |    0 |   13 |    0 |
    | Mexico  | 113910608  | 1972550    | R          |    0 |   15 |    0 |
    | Norway  | 5002942    | 385252     | R          |    0 |   17 |    0 |
    | UAE     | 8264070    | 83600      | R          |    0 |   18 |    0 |
    | UK      | 62262000   | 243610     | L          |    0 |   14 |    0 |
    | USA     | 314242000  | 9826675    | R          |    0 |   12 |    0 |
    +---------+------------+------------+------------+------+------+------+
    

    注意

    在定义被视为数字的列的长度时,始终要允许足够的大小来容纳必要的数字、小数点、符号字符、前导零等。对于像VARCHAR这样的字符串列中的值过长,通过删除一些字符来截断,可能会产生荒谬的数值。

  7. 可选地,在存储memcached数据的InnoDB表上运行报告类型的查询。

    您可以通过 SQL 查询生成报告,对任何列执行计算和测试,而不仅仅是country键列。 (因为以下示例仅使用了少数国家的数据,所以数字仅供说明目的。)以下查询返回驾驶方向为右侧的国家的平均人口和以“U”开头的国家的平均大小:

    mysql> SELECT AVG(population) FROM multicol WHERE drive_side = 'R';
    +-------------------+
    | avg(population)   |
    +-------------------+
    | 261304724.7142857 |
    +-------------------+
    
    mysql> SELECT SUM(area_sq_km) FROM multicol WHERE country LIKE 'U%';
    +-----------------+
    | sum(area_sq_km) |
    +-----------------+
    |        10153885 |
    +-----------------+
    

    因为populationarea_sq_km列存储的是字符数据而不是强类型的数值数据,所以诸如AVG()SUM()之类的函数会先将每个值转换为数字。这种方法不适用于诸如<>之类的运算符,例如,当比较基于字符的值时,9 > 1000,这与ORDER BY population DESC这样的子句所期望的不符。为了获得最准确的类型处理,请对将数值列转换为适当类型的视图执行查询。这种技术使您可以从数据库应用程序发出简单的SELECT *查询,同时确保转换、过滤和排序是正确的。以下示例显示了一个视图,可以查询以按人口降序排列的前三个国家,结果反映了multicol表中的最新数据,并将人口和面积数字视为数字:

    mysql> CREATE VIEW populous_countries AS
           SELECT
           country,
           cast(population as unsigned integer) population,
           cast(area_sq_km as unsigned integer) area_sq_km,
           drive_side FROM multicol
           ORDER BY CAST(population as unsigned integer) DESC
           LIMIT 3;
    
    mysql> SELECT * FROM populous_countries;
    +---------+------------+------------+------------+
    | country | population | area_sq_km | drive_side |
    +---------+------------+------------+------------+
    | China   | 1347350000 |    9640821 | R          |
    | India   | 1210193422 |    3287263 | L          |
    | USA     |  314242000 |    9826675 | R          |
    +---------+------------+------------+------------+
    
    mysql> DESC populous_countries;
    +------------+---------------------+------+-----+---------+-------+
    | Field      | Type                | Null | Key | Default | Extra |
    +------------+---------------------+------+-----+---------+-------+
    | country    | varchar(128)        | NO   |     |         |       |
    | population | bigint(10) unsigned | YES  |     | NULL    |       |
    | area_sq_km | int(9) unsigned     | YES  |     | NULL    |       |
    | drive_side | varchar(1)          | YES  |     | NULL    |       |
    +------------+---------------------+------+-----+---------+-------+
    

原文:dev.mysql.com/doc/refman/8.0/en/innodb-memcached-porting-memcached.html

17.20.6.2 调整 memcached 应用以适配 InnoDB memcached 插件

在将现有的memcached应用程序调整为使用daemon_memcached插件时,请考虑 MySQL 和InnoDB表的这些方面:

  • 如果键值长于几个字节,最好在InnoDB表的主键上使用数值自增列,并在包含memcached键值的列上创建唯一的二级索引可能更有效。这是因为如果主键值按排序顺序添加(就像使用自增值一样),InnoDB在大规模插入时表现最佳。主键值包含在二级索引中,如果主键是长字符串值,则会占用不必要的空间。

  • 如果您使用memcached存储多种不同类别的信息,请考虑为每种数据类型设置单独的InnoDB表。在innodb_memcache.containers表中定义额外的表标识符,并使用@@*table_id*.*key*的表示法来存储和检索来自不同表的项目。物理上划分不同类型的信息允许您调整每个表的特性,以实现最佳的空间利用率、性能和可靠性。例如,您可以为保存博客文章的表启用压缩,但不为保存缩略图图像的表启用。您可能更频繁地备份一个表,因为它包含关键数据。您可能在经常用于生成报告的表上创建额外的二级索引。

  • 最好为与daemon_memcached插件一起使用的表定义一个稳定的表定义,并永久保留这些表。对innodb_memcache.containers表的更改将在下次查询innodb_memcache.containers表时生效。容器表中的条目在启动时被处理,并且在使用@@表示法请求未识别的表标识符(由containers.name定义)时会被查询。因此,只要使用相关的表标识符,新条目就会立即可见,但对现有条目的更改需要在生效之前重新启动服务器。

  • 当您使用默认的innodb_only缓存策略时,对add()set()incr()等的调用可能会成功,但仍会触发调试消息,如while expecting 'STORED', got unexpected response 'NOT_STORED。调试消息的出现是因为新值和更新值直接发送到InnoDB表,而不保存在内存缓存中,这是由于innodb_only缓存策略导致的。

原文:dev.mysql.com/doc/refman/8.0/en/innodb-memcached-tuning.html

17.20.6.3 调整 InnoDB memcached 插件性能

因为使用InnoDBmemcached结合涉及将所有数据写入磁盘,无论是立即还是稍后,所以原始性能预计会比单独使用memcached略慢。在使用InnoDBmemcached插件时,将memcached操作的调整目标集中在实现比等效 SQL 操作更好的性能上。

基准测试表明,使用memcached接口的查询和 DML 操作(插入、更新和删除)比传统 SQL 更快。DML 操作通常会看到更大的改进。因此,首先考虑调整写入密集型应用程序以使用memcached接口。还要考虑优先适应使用快速、轻量级机制但缺乏可靠性的写入密集型应用程序。

调整 SQL 查询

最适合简单GET请求的查询类型是具有单个子句或WHERE子句中一组AND条件的查询:

SQL:
SELECT col FROM tbl WHERE key = 'key_value';

memcached:
get key_value

SQL:
SELECT col FROM tbl WHERE col1 = val1 and col2 = val2 and col3 = val3;

memcached:
# Since you must always know these 3 values to look up the key,
# combine them into a unique string and use that as the key
# for all ADD, SET, and GET operations.
key_value = val1 + ":" + val2 + ":" + val3
get key_value

SQL:
SELECT 'key exists!' FROM tbl
  WHERE EXISTS (SELECT col1 FROM tbl WHERE KEY = 'key_value') LIMIT 1;

memcached:
# Test for existence of key by asking for its value and checking if the call succeeds,
# ignoring the value itself. For existence checking, you typically only store a very
# short value such as "1".
get key_value
利用系统内存

为了获得最佳性能,请在配置为典型数据库服务器的机器上部署daemon_memcached插件,其中大部分系统 RAM 专用于InnoDB缓冲池,通过innodb_buffer_pool_size配置选项。对于具有多千兆字节缓冲池的系统,考虑提高innodb_buffer_pool_instances的值,以获得大多数操作涉及已缓存在内存中的数据时的最大吞吐量。

减少冗余 I/O

InnoDB有许多设置选项,让您在发生崩溃时可以选择高可靠性,同时在高写入工作负载期间减少 I/O 开销。例如,考虑将innodb_doublewrite设置为0,将innodb_flush_log_at_trx_commit设置为2。使用不同的innodb_flush_method设置来衡量性能。

若要减少或调整表操作的 I/O 的其他方法,请参阅第 10.5.8 节,“优化 InnoDB 磁盘 I/O”。

减少事务开销

daemon_memcached_r_batch_sizedaemon_memcached_w_batch_size的默认值为 1,旨在获得最大的结果可靠性和存储或更新数据的安全性。

根据应用程序的类型,您可能会增加这两个设置中的一个或两个,以减少频繁提交操作的开销。在繁忙的系统上,您可能会增加daemon_memcached_r_batch_size的值,知道通过 SQL 对数据的更改可能不会立即对memcached可见(也就是说,直到处理了Nget操作)。在处理每个写操作都必须可靠存储的数据时,将daemon_memcached_w_batch_size设置为1。在处理仅用于统计分析的大量更新时,可以增加该设置,其中在意外退出时丢失最后N次更新是可以接受的风险。

例如,想象一个监视穿过繁忙桥梁的交通的系统,每天记录大约 10 万辆车辆的数据。如果应用程序计算不同类型的车辆以分析交通模式,将daemon_memcached_w_batch_size1更改为100可以将提交操作的 I/O 开销减少 99%。在发生故障时,最多会丢失 100 条记录,这可能是可以接受的误差范围。如果应用程序执行每辆车的自动收费,您将把daemon_memcached_w_batch_size设置为1,以确保每个收费记录立即保存到磁盘。

由于InnoDB在磁盘上组织memcached键值的方式,如果要创建大量键,则在应用程序中按键值对数据项进行排序并按排序顺序add它们可能比以任意顺序创建键更快。

memslap命令是常规memcached分发的一部分,但不包括在daemon_memcached插件中,可用于对不同配置进行基准测试。它还可用于生成样本键值对,以在您自己的基准测试中使用。

原文:dev.mysql.com/doc/refman/8.0/en/innodb-memcached-txn.html

17.20.6.4 控制 InnoDB memcached 插件的事务行为

与传统的memcached不同,daemon_memcached插件允许您控制通过addsetincr等调用生成的数据值的耐久性。默认情况下,通过memcached接口写入的数据会存储到磁盘,并且调用get会从磁盘返回最新的值。尽管默认行为并不提供最佳的原始性能,但与InnoDB表的 SQL 接口相比,仍然快速。

随着您使用daemon_memcached插件的经验增加,您可以考虑放宽非关键数据类的耐久性设置,以便在发生故障时可能会丢失一些更新的值,或者返回略有过时的数据。

提交频率

耐久性和原始性能之间的一个权衡是新数据和更改数据的提交频率。如果数据很关键,应立即提交,以便在意外退出或故障时安全。如果数据不那么关键,例如在意外退出后重置的计数器或您可以承受丢失的日志数据,您可能更喜欢更少的提交频率可用的更高原始吞吐量。

memcached操作在底层InnoDB表中插入、更新或删除数据时,如果daemon_memcached_w_batch_size=1,更改可能会立即提交到InnoDB表中,或者稍后一段时间(如果daemon_memcached_w_batch_size的值大于 1)。在任何情况下,更改都无法回滚。如果您增加daemon_memcached_w_batch_size的值以避免在繁忙时期产生高 I/O 开销,当工作负载减少时,提交可能变得不频繁。作为一项安全措施,后台线程会定期自动提交通过memcached API 进行的更改。这个间隔由innodb_api_bk_commit_interval配置选项控制,默认设置为5秒。

memcached操作在底层InnoDB表中插入或更新数据时,由于新值仍然保留在内存缓存中,即使尚未在 MySQL 端提交,其他memcached请求立即可以看到更改的数据。

事务隔离

当 memcached 操作(如 getincr)导致基础 InnoDB 表上的查询或 DML 操作时,您可以控制操作是否看到表中最新写入的数据,仅看到已提交的数据,或事务隔离级别的其他变化。使用 innodb_api_trx_level 配置选项来控制此功能。此选项指定的数字值对应于隔离级别,如 REPEATABLE READ。有关其他设置的信息,请参阅 innodb_api_trx_level 选项的描述。

严格的隔离级别确保您检索的数据不会被回滚或突然更改,导致后续查询返回不同的值。然而,严格的隔离级别需要更大的锁定开销,可能会导致等待。对于不使用长时间事务的 NoSQL 风格应用程序,通常可以使用默认隔离级别或切换到较不严格的隔禅级别。

禁用 memcached 的 DML 操作的行锁。

memcached 请求通过 daemon_memcached 插件导致对 InnoDB 表的查询或 DML 操作时,可以使用 innodb_api_disable_rowlock 选项来禁用行锁。默认情况下,innodb_api_disable_rowlock 设置为 OFF,这意味着 memcached 请求行锁用于 getset 操作。当 innodb_api_disable_rowlock 设置为 ON 时,memcached 请求表锁而不是行锁。

innodb_api_disable_rowlock 选项不是动态的。必须在启动时在 mysqld 命令行上指定,或在 MySQL 配置文件中输入。

允许或禁止 DDL。

默认情况下,可以在 daemon_memcached 插件使用的表上执行 DDL 操作,如 ALTER TABLE。为避免这些表用于高吞吐量应用程序时潜在的减速,启用 innodb_api_enable_mdl 来禁用这些表上的 DDL 操作。当通过 memcached 和 SQL 访问相同的表时,此选项不太合适,因为它会阻止对表进行 CREATE INDEX 语句的操作,这对运行报表查询可能很重要。

将数据存储在磁盘、内存中,或两者兼而有之。

innodb_memcache.cache_policies 表指定是否将通过 memcached 接口写入的数据存储到磁盘(innodb_only,默认);仅存��在内存中,如传统的 memcachedcache_only);或两者兼而有之(caching)。

使用caching设置,如果memcached在内存中找不到一个键,它会在InnoDB表中搜索该值。在caching设置下返回的get调用的值可能已经过时,如果这些值在InnoDB表中更新但尚未从内存缓存中过期。

缓存策略可以独立设置为getset(包括incrdecr)、deleteflush操作。

例如,您可以允许getset操作同时查询或更新表和memcached内存缓存(使用caching设置),同时使deleteflush或两者仅在内存副本上操作(使用cache_only设置)。这样,删除或刷新项目仅会使项目从缓存中过期,并且下次请求项目时将从InnoDB表中返回最新值。

mysql> SELECT * FROM innodb_memcache.cache_policies;
+--------------+-------------+-------------+---------------+--------------+
| policy_name  | get_policy  | set_policy  | delete_policy | flush_policy |
+--------------+-------------+-------------+---------------+--------------+
| cache_policy | innodb_only | innodb_only | innodb_only   | innodb_only  |
+--------------+-------------+-------------+---------------+--------------+

mysql> UPDATE innodb_memcache.cache_policies SET set_policy = 'caching'
       WHERE policy_name = 'cache_policy';

innodb_memcache.cache_policies的值只在启动时读取。在更改此表中的值后,卸载并重新安装daemon_memcached插件以确保更改生效。

mysql> UNINSTALL PLUGIN daemon_memcached;

mysql> INSTALL PLUGIN daemon_memcached soname "libmemcached.so";

原文:dev.mysql.com/doc/refman/8.0/en/innodb-memcached-dml.html

17.20.6.5 将 DML 语句调整为 memcached 操作

基准测试表明,daemon_memcached 插件加速了 DML 操作(插入、更新和删除)比加速查询更多。因此,考虑将初始开发工作重点放在写入密集型且 I/O 限制的应用程序上,并寻找机会在新的写入密集型应用程序中使用带有 daemon_memcached 插件的 MySQL。

单行 DML 语句是最容易转换为 memcached 操作的语句类型。INSERT 变为 addUPDATE 变为 setincrdecr,而 DELETE 变为 delete。这些操作通过 memcached 接口发出时,保证只影响一行,因为 key 在表内是唯一的。

在以下的 SQL 示例中,t1 指的是基于 innodb_memcache.containers 表中配置的 memcached 操作所使用的表。key 指的是列在 key_columns 下列出的列,val 指的是列在 value_columns 下列出的列。

INSERT INTO t1 (key,val) VALUES (*some_key*,*some_value*);
SELECT val FROM t1 WHERE key = *some_key*;
UPDATE t1 SET val = *new_value* WHERE key = *some_key*;
UPDATE t1 SET val = val + x WHERE key = *some_key*;
DELETE FROM t1 WHERE key = *some_key*;

下面的 TRUNCATE TABLEDELETE 语句,用于从表中删除所有行,对应于 flush_all 操作,其中 t1 被配置为 memcached 操作的表,就像前面的示例中一样。

TRUNCATE TABLE t1;
DELETE FROM t1;

原文:dev.mysql.com/doc/refman/8.0/en/innodb-memcached-ddl.html

17.20.6.6 在底层 InnoDB 表上执行 DML 和 DDL 语句

您可以通过标准 SQL 接口访问底层的InnoDB表(默认为test.demo_test)。但是,存在一些限制:

  • 当查询通过memcached接口访问的表时,请记住memcached操作可以配置为定期提交,而不是在每次写操作后立即提交。此行为由daemon_memcached_w_batch_size选项控制。如果此选项设置为大于1的值,请使用READ UNCOMMITTED查询以查找刚刚插入的行。

    mysql> SET SESSSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
    
    mysql> SELECT * FROM demo_test;
    +------+------+------+------+-----------+------+------+------+------+------+------+
    | cx   | cy   | c1   | cz   | c2        | ca   | CB   | c3   | cu   | c4   | C5   |
    +------+------+------+------+-----------+------+------+------+------+------+------+
    | NULL | NULL | a11  | NULL | 123456789 | NULL | NULL |   10 | NULL |    3 | NULL |
    +------+------+------+------+-----------+------+------+------+------+------+------+
    
  • 当使用 SQL 修改通过memcached接口访问的表时,您可以配置memcached操作定期启动新事务,而不是每次读操作都启动事务。此行为由daemon_memcached_r_batch_size选项控制。如果此选项设置为大于1的值,则使用 SQL 对表进行的更改不会立即对memcached操作可见。

  • 对于事务中的所有操作,InnoDB表都会被 IS(意向共享)或 IX(意向排他)锁定。如果您将daemon_memcached_r_batch_sizedaemon_memcached_w_batch_size从默认值1大幅增加,那么表在每个操作之间很可能被锁定,从而阻止对表的 DDL 语句的执行。

17.20.7 InnoDB memcached 插件和复制

原文:dev.mysql.com/doc/refman/8.0/en/innodb-memcached-replication.html

因为daemon_memcached插件支持 MySQL 的二进制日志,源服务器通过memcached接口可以进行备份复制,平衡读取工作负载,并实现高可用性。所有memcached命令都支持二进制日志记录。

您无需在副本服务器上设置daemon_memcached插件。此配置的主要优势是增加源端的写入吞吐量。复制机制的速度不受影响。

以下各节显示了在使用daemon_memcached插件进行 MySQL 复制时如何使用二进制日志功能。假定您已完成第 17.20.3 节“设置 InnoDB memcached 插件”中描述的设置。

启用 InnoDB memcached 二进制日志

  1. 要在 MySQL 的二进制日志中使用daemon_memcached插件,请在源服务器上启用innodb_api_enable_binlog配置选项。此选项只能在服务器启动时设置。您还必须在源服务器上使用--log-bin选项启用 MySQL 的二进制日志。您可以将这些选项添加到 MySQL 配置文件中,或者在mysqld命令行中添加。

    mysqld ... --log-bin -–innodb_api_enable_binlog=1
    
  2. 配置源服务器和副本服务器,如第 19.1.2 节“基于二进制日志文件位置的复制设置”中所述。

  3. 使用mysqldump创建源数据快照,并将快照同步到副本服务器。

    source $> mysqldump --all-databases --lock-all-tables > dbdump.db
    replica $> mysql < dbdump.db
    
  4. 在源服务器上,执行SHOW MASTER STATUS以获取源二进制日志坐标。

    mysql> SHOW MASTER STATUS;
    
  5. 在副本服务器上,使用CHANGE REPLICATION SOURCE TO语句(从 MySQL 8.0.23 开始)或CHANGE MASTER TO语句(MySQL 8.0.23 之前)设置使用源二进制日志坐标的副本服务器。

    mysql> CHANGE MASTER TO
           MASTER_HOST='localhost',
           MASTER_USER='root',
           MASTER_PASSWORD='',
           MASTER_PORT = 13000,
           MASTER_LOG_FILE='0.000001,
           MASTER_LOG_POS=114;
    
    Or from MySQL 8.0.23:
    mysql> CHANGE REPLICATION SOURCE TO
           SOURCE_HOST='localhost',
           SOURCE_USER='root',
           SOURCE_PASSWORD='',
           SOURCE_PORT = 13000,
           SOURCE_LOG_FILE='0.000001,
           SOURCE_LOG_POS=114;
    
  6. 启动副本。

    mysql> START SLAVE;
    Or from MySQL 8.0.22:
    mysql> START REPLICA;
    

    如果错误日志输出类似于以下内容,则副本已准备好进行复制。

    2013-09-24T13:04:38.639684Z 49 [Note] Replication I/O thread: connected to
    source 'root@localhost:13000', replication started in log '0.000001'
    at position 114
    

测试 InnoDB memcached 复制配置

该示例演示了如何使用memcached和 telnet 测试InnoDB memcached复制配置,以插入、更新和删除数据。使用 MySQL 客户端验证源服务器和副本服务器上的结果。

该示例使用了innodb_memcached_config.sql配置脚本在daemon_memcached插件的初始设置期间创建的demo_test表。demo_test表包含一个示例记录。

  1. 使用set命令插入一个具有键test1、标志值10、过期值0、cas 值 1 和值t1的记录。

    telnet 127.0.0.1 11211
    Trying 127.0.0.1...
    Connected to 127.0.0.1.
    Escape character is '^]'.
    set test1 10 0 1
    t1
    STORED
    
  2. 在源服务器上,检查记录是否插入到demo_test表中。假设demo_test表之前未被修改,应该有两条记录。一个具有键AA的示例记录,以及刚刚插入的具有键test1的记录。c1列映射到键,c2列映射到值,c3列映射到标志值,c4列映射到 cas 值,c5列映射到过期时间。过期时间设置为 0,因为未使用。

    mysql> SELECT * FROM test.demo_test;
    +-------+--------------+------+------+------+
    | c1    | c2           | c3   | c4   | c5   |
    +-------+--------------+------+------+------+
    | AA    | HELLO, HELLO |    8 |    0 |    0 |
    | test1 | t1           |   10 |    1 |    0 |
    +-------+--------------+------+------+------+
    
  3. 检查验证相同记录是否被复制到副本服务器。

    mysql> SELECT * FROM test.demo_test;
    +-------+--------------+------+------+------+
    | c1    | c2           | c3   | c4   | c5   |
    +-------+--------------+------+------+------+
    | AA    | HELLO, HELLO |    8 |    0 |    0 |
    | test1 | t1           |   10 |    1 |    0 |
    +-------+--------------+------+------+------+
    
  4. 使用set命令将键更新为new的值。

    telnet 127.0.0.1 11211
    Trying 127.0.0.1...
    Connected to 127.0.0.1.
    Escape character is '^]'.
    set test1 10 0 2
    new
    STORED
    

    更新被复制到副本服务器(注意cas值也被更新)。

    mysql> SELECT * FROM test.demo_test;
    +-------+--------------+------+------+------+
    | c1    | c2           | c3   | c4   | c5   |
    +-------+--------------+------+------+------+
    | AA    | HELLO, HELLO |    8 |    0 |    0 |
    | test1 | new          |   10 |    2 |    0 |
    +-------+--------------+------+------+------+
    
  5. 使用delete命令删除test1记录。

    telnet 127.0.0.1 11211
    Trying 127.0.0.1...
    Connected to 127.0.0.1.
    Escape character is '^]'.
    delete test1
    DELETED
    

    delete操作被复制到副本时,副本上的test1记录也被删除。

    mysql> SELECT * FROM test.demo_test;
    +----+--------------+------+------+------+
    | c1 | c2           | c3   | c4   | c5   |
    +----+--------------+------+------+------+
    | AA | HELLO, HELLO |    8 |    0 |    0 |
    +----+--------------+------+------+------+
    
  6. 使用flush_all命令从表中删除所有行。

    telnet 127.0.0.1 11211
    Trying 127.0.0.1...
    Connected to 127.0.0.1.
    Escape character is '^]'.
    flush_all
    OK
    
    mysql> SELECT * FROM test.demo_test;
    Empty set (0.00 sec)
    
  7. 使用 telnet 连接到源服务器并输入两条新记录。

    telnet 127.0.0.1 11211
    Trying 127.0.0.1...
    Connected to 127.0.0.1.
    Escape character is '^]'
    set test2 10 0 4
    again
    STORED
    set test3 10 0 5
    again1
    STORED
    
  8. 确认两条记录是否被复制到副本服务器。

    mysql> SELECT * FROM test.demo_test;
    +-------+--------------+------+------+------+
    | c1    | c2           | c3   | c4   | c5   |
    +-------+--------------+------+------+------+
    | test2 | again        |   10 |    4 |    0 |
    | test3 | again1       |   10 |    5 |    0 |
    +-------+--------------+------+------+------+
    
  9. 使用flush_all命令从表中删除所有行。

    telnet 127.0.0.1 11211
    Trying 127.0.0.1...
    Connected to 127.0.0.1.
    Escape character is '^]'.
    flush_all
    OK
    
  10. 检查确保flush_all操作在副本服务器上被复制。

    mysql> SELECT * FROM test.demo_test;
    Empty set (0.00 sec)
    

InnoDB memcached二进制日志注释

二进制日志格式:

  • 大多数memcached操作都映射到 DML 语句(类似于插入、删除、更新)。由于 MySQL 服务器没有实际的 SQL 语句在处理,所有memcached命令(除了flush_all)使用基于行的复制(RBR)日志记录,这与任何服务器binlog_format设置无关。

  • memcachedflush_all命令映射到 MySQL 5.7 及更早版本的TRUNCATE TABLE命令。由于 DDL 命令只能使用基于语句的日志记录,flush_all命令通过发送TRUNCATE TABLE语句来复制。在 MySQL 8.0 及更高版本中,flush_all映射到DELETE,但仍通过发送TRUNCATE TABLE语句来复制。

事务:

  • 事务的概念通常不是memcached应用的一部分。为了性能考虑,daemon_memcached_r_batch_sizedaemon_memcached_w_batch_size用于控制读取和写入事务的批处理大小。这些设置不影响复制。在底层InnoDB表上的每个 SQL 操作在成功完成后被复制。

  • daemon_memcached_w_batch_size的默认值为1,这意味着每个memcached写操作立即提交。这个默认设置会产生一定的性能开销,以避免在源服务器和副本服务器上可见的数据不一致。复制的记录在副本服务器上始终立即可用。如果将daemon_memcached_w_batch_size设置为大于1的值,则通过memcached插入或更新的记录在源服务器上不会立即可见;在提交之前在源服务器上查看记录,请发出SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

17.20.8 InnoDB memcached 插件内部

原文:dev.mysql.com/doc/refman/8.0/en/innodb-memcached-internals.html

InnoDB memcached 插件的 InnoDB API

InnoDB memcached引擎通过InnoDB API 访问InnoDB,其中大部分直接采用自嵌入式InnoDBInnoDB API 函数作为回调函数传递给InnoDB memcached引擎。 InnoDB API 函数直接访问InnoDB表,大多数是 DML 操作,除了TRUNCATE TABLE

memcached命令通过InnoDB memcached API 实现。以下表格概述了如何将memcached命令映射到 DML 或 DDL 操作。

表 17.27 memcached 命令及相关的 DML 或 DDL 操作

memcached 命令 DML 或 DDL 操作
get 读取/获取命令
set 一次搜索,然后是INSERTUPDATE(取决于键是否存在)
add 一次搜索,然后是INSERTUPDATE
replace 一次搜索,然后是UPDATE
append 一次搜索,然后是UPDATE(在UPDATE之前将数据追加到结果中)
prepend 一次搜索,然后是UPDATE(在UPDATE之前将数据前置到结果中)
incr 一次搜索,然后是UPDATE
decr 一次搜索,然后是UPDATE
delete 一次搜索,然后是DELETE
flush_all TRUNCATE TABLE(DDL)
memcached 命令 DML 或 DDL 操作

InnoDB memcached 插件配置表

本节描述了daemon_memcached插件使用的配置表。 cache_policies表,config_options表和containers表由innodb_memcached_config.sql配置脚本在innodb_memcache数据库中创建。

mysql> USE innodb_memcache;
Database changed
mysql> SHOW TABLES;
+---------------------------+
| Tables_in_innodb_memcache |
+---------------------------+
| cache_policies            |
| config_options            |
| containers                |
+---------------------------+

cache_policies 表

cache_policies表定义了InnoDB memcached安装的缓存策略。您可以在单个缓存策略中为getsetdeleteflush操作指定单独的策略。所有操作的默认设置为innodb_only

  • innodb_only: 使用InnoDB作为数据存储。

  • cache_only: 使用memcached引擎作为数据存储。

  • caching: 同时使用InnoDBmemcached引擎作为数据存储。在这种情况下,如果memcached在内存中找不到键,则会在InnoDB表中搜索该值。

  • disable: 禁用缓存。

表 17.28 cache_policies 列

描述
policy_name 缓存策略的名称。默认缓存策略名称为cache_policy
get_policy get 操作的缓存策略。有效值为innodb_onlycache_onlycachingdisabled。默认设置为innodb_only
set_policy set 操作的缓存策略。有效值为innodb_onlycache_onlycachingdisabled。默认设置为innodb_only
delete_policy 删除操作的缓存策略。有效值为innodb_onlycache_onlycachingdisabled。默认设置为innodb_only
flush_policy 刷新操作的缓存策略。有效值为innodb_onlycache_onlycachingdisabled。默认设置为innodb_only

config_options 表

config_options表存储可以使用 SQL 在运行时更改的与memcached相关的设置。支持的配置选项是separatortable_map_delimiter

表 17.29 config_options 列

描述

| Name | memcached相关配置选项的名称。config_options表支持以下配置选项:

  • separator:用于将长字符串的值分隔为单独的值的分隔符,当定义了多个value_columns时。默认情况下,分隔符是&#124;字符。例如,如果您将col1, col2定义为值列,并将&#124;定义为分隔符,则可以发出以下memcached命令将值分别插入到col1col2中:

    set keyx 10 0 19
    valuecolx&#124;valuecoly
    

    valuecol1x存储在col1中,valuecoly存储在col2中。

  • table_map_delimiter:在使用@@符号访问特定表中的键时,用于分隔模式名称和表名称的字符。例如,@@t1.some_key@@t2.some_key具有相同的键值,但存储在不同的表中。

|

Value 分配给与memcached相关的配置选项的值。

containers 表

containers表是三个配置表中最重要的一个。用于存储memcached值的每个InnoDB表必须在containers表中有一个条目。该条目提供了InnoDB表列和容器表列之间的映射,这对于memcachedInnoDB表一起工作是必需的。

containers表包含test.demo_test表的默认条目,该表是由innodb_memcached_config.sql配置脚本创建的。要使用daemon_memcached插件与自己的InnoDB表,必须在containers表中创建一个条目。

表 17.30 containers 列

描述
name 分配给容器的名称。如果没有使用@@符号按名称请求InnoDB表,则daemon_memcached插件将使用具有containers.name值为defaultInnoDB表。如果没有这样的条目,则按name(升序)字母顺序排列的containers表中的第一个条目确定默认的InnoDB表。
db_schema 包含InnoDB表的数据库的名称。这是一个必填值。
db_table 存储memcached值的InnoDB表的名称。这是一个必填值。
key_columns 包含memcached操作查找键值的InnoDB表中的列。这是一个必填值。
value_columns 存储memcached数据的InnoDB表列(一个或多个)。可以使用innodb_memcached.config_options表中指定的分隔符字符指定多个列。默认情况下,分隔符是一个竖线字符(“
flags 用作memcached标志(与主值一起存储和检索的用户定义的数值)的InnoDB表列。如果memcached值映射到多个列,则标志值可以用作某些操作(如incrprepend)的列指定符,以便在指定列上执行操作。例如,如果你已将value_columns映射到三个InnoDB表列,并且只想要增量操作在一个列上执行,请使用flags列指定该列。如果你不使用flags列,请设置值为0以指示未使用。
cas_column 存储比较和交换(cas)值的InnoDB表列。cas_column值与memcached如何将请求哈希到不同服务器并在内存中缓存数据有关。由于InnoDB memcached插件与单个memcached守护程序紧密集成,并且内存缓存机制由 MySQL 和 InnoDB 缓冲池处理,因此很少需要此列。如果你不使用此列,请设置值为0以指示未使用。
expire_time_column 存储过期值的InnoDB表列。expire_time_column值与memcached如何将请求哈希到不同服务器并在内存中缓存数据有关。由于InnoDB memcached插件与单个memcached守护程序紧密集成,并且内存缓存机制由 MySQL 和 InnoDB 缓冲池处理,因此很少需要此列。如果你不使用此列,请设置值为0以指示未使用。最大过期时间定义为INT_MAX32或 2147483647 秒(约 68 年)。
unique_idx_name_on_key 索引在关键列上的名称。它必须是一个唯一索引。它可以是主键或次要索引。最好使用InnoDB表的主键。使用主键可以避免在使用次要索引时进行查找。你不能为memcached查找创建一个覆盖索引;如果你尝试在键和值列上定义一个复合次要索引,InnoDB会返回错误。
容器表列约束
  • 您必须为db_schemadb_namekey_columnsvalue_columnsunique_idx_name_on_key提供值。如果未使用,将flagscas_columnexpire_time_column设置为0。如果未这样做,可能会导致设置失败。

  • key_columns: memcached键的最大限制为 250 个字符,由memcached强制执行。映射键必须是非空的CHARVARCHAR类型。

  • value_columns: 必须映射到CHARVARCHARBLOB列。没有长度限制,值可以为 NULL。

  • cas_column: cas值是 64 位整数。必须映射到至少 8 字节的BIGINT。如果您不使用此列,请设置值为0以指示未使用。

  • expiration_time_column: 必须映射到至少 4 字节的INTEGER。过期时间定义为 Unix 时间的 32 位整数(自 1970 年 1 月 1 日以来的秒数作为 32 位值),或从当前时间开始的秒数。对于后者,秒数不得超过 606024*30(30 天内的秒数)。如果客户端发送的数字较大,则服务器将其视为真实的 Unix 时间值,而不是从当前时间的偏移量。如果不使用此列,请设置值为0以指示未使用。

  • flags: 必须映射到至少 32 位的INTEGER,可以为 NULL。如果您不使用此列,请设置值为0以指示未使用。

在插件加载时执行预检查以强制执行列约束。如果发现不匹配,插件将不加载。

多值列映射
  • 在插件初始化期间,当InnoDB memcached配置为containers表中定义的信息时,将验证containers.value_columns中定义的每个映射列与映射的InnoDB表。如果映射了多个InnoDB表列,则会检查以确保每个列存在且为正确类型。

  • 在运行时,对于memcached插入操作,如果有比映射列数更多的分隔值,则仅取映射值的数量。例如,如果有六个映射列,并且提供了七个分隔值,则仅取前六个分隔值。第七个分隔值将被忽略。

  • 如果分隔值少于映射的列数,未填充的列将被设置为 NULL。如果无法将未填充的列设置为 NULL,则插入操作将失败。

  • 如果一个表的列数多于映射值,额外的列不会影响结果。

demo_test 示例表

innodb_memcached_config.sql 配置脚本在 test 数据库中创建了一个 demo_test 表,可用于在安装InnoDB memcached 插件后立即验证安装。

innodb_memcached_config.sql 配置脚本还在 innodb_memcache.containers 表中为 demo_test 表创建了一个条目。

mysql> SELECT * FROM innodb_memcache.containers\G
*************************** 1\. row ***************************
                  name: aaa
             db_schema: test
              db_table: demo_test
           key_columns: c1
         value_columns: c2
                 flags: c3
            cas_column: c4
    expire_time_column: c5
unique_idx_name_on_key: PRIMARY 
mysql> SELECT * FROM test.demo_test;
+----+------------------+------+------+------+
| c1 | c2               | c3   | c4   | c5   |
+----+------------------+------+------+------+
| AA | HELLO, HELLO     |    8 |    0 |    0 |
+----+------------------+------+------+------+

17.20.9 解决 InnoDB memcached 插件问题

原文:dev.mysql.com/doc/refman/8.0/en/innodb-memcached-troubleshoot.html

本节描述了在使用InnoDB memcached插件时可能遇到的问题。

  • 如果在 MySQL 错误日志中遇到以下错误,则服务器可能无法启动:

    设置打开文件数的限制失败。尝试以 root 用户身份运行或请求较小的 maxconns 值。

    错误消息来自memcached守护程序。一个解决方案是提高操作系统打开文件数的限制。检查和增加打开文件限制的命令因操作系统而异。以下示例显示了 Linux 和 macOS 的命令:

    # Linux
    $> ulimit -n
    1024
    $> ulimit -n 4096
    $> ulimit -n
    4096
    
    # macOS
    $> ulimit -n
    256
    $> ulimit -n 4096
    $> ulimit -n
    4096
    

    另一种解决方案是减少允许memcached守护程序的并发连接数。为此,在 MySQL 配置文件中的daemon_memcached_option配置参数中编码-c memcached选项。-c选项的默认值为 1024。

    [mysqld]
    ...
    loose-daemon_memcached_option='-c 64'
    
  • 要解决memcached守护程序无法存储或检索InnoDB表数据的问题,请在 MySQL 配置文件的daemon_memcached_option配置参数中编码-vvv memcached选项。检查 MySQL 错误日志以获取与memcached操作相关的调试输出。

    [mysqld]
    ...
    loose-daemon_memcached_option='-vvv'
    
  • 如果指定用于保存memcached值的列的数据类型错误,例如数字类型而不是字符串类型,则尝试存储键值对将失败,而不会显示特定的错误代码或消息。

  • 如果daemon_memcached插件导致 MySQL 服务器启动问题,您可以在故障排除时通过在 MySQL 配置文件的[mysqld]组下添加以下行来临时禁用daemon_memcached插件:

    daemon_memcached=OFF
    

    例如,如果在运行innodb_memcached_config.sql配置脚本设置必要的数据库和表之前运行INSTALL PLUGIN语句,则服务器可能会意外退出并无法启动。如果在innodb_memcache.containers表中错误配置条目,服务器也可能无法启动。

    要卸载 MySQL 实例的memcached插件,请发出以下语句:

    mysql> UNINSTALL PLUGIN daemon_memcached;
    
  • 如果在同一台机器上运行多个 MySQL 实例,并且每个实例都启用了daemon_memcached插件,请使用daemon_memcached_option配置参数为每个daemon_memcached插件指定一个独特的memcached端口。

  • 如果一个 SQL 语句无法找到InnoDB表或在表中找不到数据,但memcached API 调用检索到了预期的数据,那么可能是在innodb_memcache.containers表中缺少了InnoDB表的条目,或者您可能没有通过使用@@*table_id*标记发出getset请求来切换到正确的InnoDB表。如果您在之后没有重新启动 MySQL 服务器的情况下更改了innodb_memcache.containers表中的现有条目,也可能会出现这个问题。自由形式的存储机制足够灵活,即使守护程序正在使用将值存储在单列中的test.demo_test表,您对存储或检索多列值(如col1|col2|col3)的请求可能仍然有效。

  • 在为daemon_memcached插件定义自己的InnoDB表时,如果表中的列被定义为NOT NULL,请确保在将表的记录插入innodb_memcache.containers表时为NOT NULL列提供值。如果innodb_memcache.containers记录的INSERT语句包含的分隔值少于映射列的数量,未填充的列将被设置为NULL。尝试将NULL值插入NOT NULL列会导致INSERT失败,这可能只有在重新初始化daemon_memcached插件以应用对innodb_memcache.containers表的更改后才会显现。

  • 如果innodb_memcached.containers表的cas_columnexpire_time_column字段设置为NULL,则在尝试加载memcached插件时会返回以下错误:

    InnoDB_Memcached: column 6 in the entry for config table 'containers' in
    database 'innodb_memcache' has an invalid NULL value.
    

    memcached插件拒绝在cas_columnexpire_time_column列中使用NULL。当这些列未使用时,将这些列的值设置为0

  • 随着memcached键和值的长度增加,您可能会遇到大小和长度限制。

    • 当键超过 250 字节时,memcached操作会返回错误。这是memcached中当前的固定限制。

    • 如果值的大小超过 768 字节、3072 字节或半个innodb_page_size值,可能会遇到InnoDB表限制。这些限制主要适用于如果您打算在值列上创建索引以使用 SQL 运行生成报表的查询时。有关详细信息,请参见第 17.22 节,“InnoDB 限制”。

    • 键-值组合的最大大小为 1 MB。

  • 如果在不同版本的 MySQL 服务器之间共享配置文件,并且使用daemon_memcached插件的最新配置选项可能会导致在旧的 MySQL 版本上启动错误。为避免兼容性问题,请在选项名称前使用loose前缀。例如,使用loose-daemon_memcached_option='-c 64'而不是daemon_memcached_option='-c 64'

  • 没有限制或检查来验证字符集设置。memcached以字节形式存储和检索键和值,因此不受字符集的影响。但是,您必须确保memcached客户端和 MySQL 表使用相同的字符集。

  • memcached连接被阻止访问包含索引虚拟列的表。访问索引虚拟列需要回调到服务器,但memcached连接无法访问服务器代码。

17.21 InnoDB 故障排除

原文:dev.mysql.com/doc/refman/8.0/en/innodb-troubleshooting.html

17.21.1 故障排除 InnoDB I/O 问题

17.21.2 故障排除恢复失败

17.21.3 强制 InnoDB 恢复

17.21.4 故障排除 InnoDB 数据字典操作

17.21.5 InnoDB 错误处理

以下一般准则适用于故障排除 InnoDB 问题:

  • 当操作失败或怀疑存在 bug 时,请查看 MySQL 服务器错误日志(参见 7.4.2 “错误日志”)。服务器错误消息参考 提供了一些常见的 InnoDB 特定错误的故障排除信息。

  • 如果故障与死锁有关,请启用 innodb_print_all_deadlocks 选项运行,以便将每个死锁的详细信息打印到 MySQL 服务器错误日志中。有关死锁的信息,请参见 17.7.5 “InnoDB 中的死锁”。

  • 如果问题与 InnoDB 数据字典有关,请参见 17.21.4 “故障排除 InnoDB 数据字典操作”。

  • 在故障排除时,通常最好从命令提示符下运行 MySQL 服务器,而不是通过 mysqld_safe 或作为 Windows 服务运行。然后您可以看到 mysqld 打印到控制台的内容,从而更好地了解发生了什么。在 Windows 上,使用 --console 选项启动 mysqld,将输出定向到控制台窗口。

  • 启用 InnoDB Monitors 以获取有关问题的信息(参见 17.17 “InnoDB Monitors”)。如果问题与性能有关,或者服务器似乎挂起,您应该启用标准 Monitor 以打印有关 InnoDB 内部状态的信息。如果问题与锁有关,请启用 Lock Monitor。如果问题与表创建、表空间或数据字典操作有关,请参考 InnoDB 信息模式系统表 来检查 InnoDB 内部数据字典的内容。

    InnoDB 在以下情况下临时启用标准 InnoDB Monitor 输出:

    • 一个长时间的信号量等待

    • InnoDB在缓冲池中找不到空闲块。

    • 缓冲池超过67%被锁堆或自适应哈希索引占用。

  • 如果你怀疑某个表损坏,运行CHECK TABLE命令检查该表。

17.21.1 解决 InnoDB I/O 问题

原文:dev.mysql.com/doc/refman/8.0/en/error-creating-innodb.html

处理InnoDB I/O 问题的故障排除步骤取决于问题发生的时间:MySQL 服务器启动期间,或者在正常操作期间,当 DML 或 DDL 语句由于文件系统级别的问题而失败时。

初始化问题

如果InnoDB在尝试初始化其表空间或日志文件时出现问题,请删除InnoDB创建的所有文件:所有ibdata文件和所有重做日志文件(MySQL 8.0.30 及更高版本中的#ib_redo*N*文件或早期版本中的ib_logfile文件)。如果您创建了任何InnoDB表,还要从 MySQL 数据库目录中删除任何.ibd文件。然后尝试重新初始化InnoDB。为了进行最简单的故障排除,请从命令提示符启动 MySQL 服务器,以便查看发生了什么。

运行时问题

如果InnoDB在文件操作期间打印操作系统错误,通常问题有以下解决方案之一:

  • 确保InnoDB数据文件目录和InnoDB日志目录存在。

  • 确保mysqld有权限在这些目录中创建文件。

  • 确保mysqld可以读取正确的my.cnfmy.ini选项文件,以便它以您指定的选项启动。

  • 确保磁盘未满,并且未超出任何磁盘配额。

  • 确保您为子目录和数据文件指定的名称不冲突。

  • 仔细检查innodb_data_home_dirinnodb_data_file_path值的语法。特别是,在innodb_data_file_path选项中的任何MAX值都是一个硬限制,超过该限制会导致致命错误。

17.21.2 故障恢复失败的故障排除

原文:dev.mysql.com/doc/refman/8.0/en/innodb-troubleshooting-recovery.html

从 MySQL 8.0.26 开始,在重做日志恢复完成并且数据字典动态元数据(srv_dict_metadata)转移到数据字典表(dict_table_t)对象之前,不允许进行检查点和推进检查点 LSN。如果在恢复期间或恢复后(但在数据字典动态元数据转移到数据字典表对象之前)重做日志空间不足,可能需要进行innodb_force_recovery重启,至少从SRV_FORCE_NO_IBUF_MERGE设置开始,或者在失败的情况下,从SRV_FORCE_NO_LOG_REDO设置开始。如果在这种情况下innodb_force_recovery重启失败,可能需要从备份中恢复。(Bug #32200595)

17.21.3 强制 InnoDB 恢复

原文:dev.mysql.com/doc/refman/8.0/en/forcing-innodb-recovery.html

为了调查数据库页面损坏,您可以使用 SELECT ... INTO OUTFILE 从数据库中导出表。通常,以这种方式获得的大部分数据是完整的。严重的损坏可能会导致 SELECT * FROM *tbl_name* 语句或 InnoDB 后台操作意外退出或断言,甚至导致 InnoDB 回滚恢复崩溃。在这种情况下,您可以使用 innodb_force_recovery 选项来强制 InnoDB 存储引擎启动,同时阻止后台操作运行,以便您可以导出表。例如,您可以在重新启动服务器之前将以下行添加到您的选项文件的 [mysqld] 部分中:

[mysqld]
innodb_force_recovery = 1

有关使用选项文件的信息,请参见 Section 6.2.2.2, “Using Option Files”。

警告

仅在紧急情况下将 innodb_force_recovery 设置为大于 0 的值,以便您可以启动 InnoDB 并导出表。在这样做之前,请确保您有数据库的备份副本,以防需要重新创建它。值为 4 或更大可能会永久损坏数据文件。仅在成功在数据库的单独物理副本上测试设置后,才在生产服务器实例上使用大于 4 的 innodb_force_recovery 设置。在强制 InnoDB 恢复时,您应始终从 innodb_force_recovery=1 开始,并根据需要逐渐增加值。

innodb_force_recovery 默认为 0(正常启动,无需强制恢复)。innodb_force_recovery 允许的非零值为 1 到 6。较大的值包含较小值的功能。例如,值为 3 包含值为 1 和 2 的所有功能。

如果您能够使用值为 3 或更低的 innodb_force_recovery 导出表,那么您相对安全,只有一些损坏的单个页面上的数据丢失。值为 4 或更大被认为是危险的,因为数据文件可能会永久损坏。值为 6 被认为是极端的,因为数据库页面处于过时状态,这反过来可能会在 B 树 和其他数据库结构中引入更多损坏。

作为安全措施,当innodb_force_recovery大于 0 时,InnoDB会阻止INSERTUPDATEDELETE操作。设置为 4 或更高的innodb_force_recovery值会将InnoDB置于只读模式。

  • 1 (SRV_FORCE_IGNORE_CORRUPT)

    让服务器即使检测到损坏的页面也能继续运行。尝试使SELECT * FROM * tbl_name *跳过损坏的索引记录和页面,有助于导出表格。

  • 2 (SRV_FORCE_NO_BACKGROUND)

    阻止主线程和任何清理线程运行。如果在清理操作期间发生意外退出,此恢复值将阻止它。

  • 3 (SRV_FORCE_NO_TRX_UNDO)

    在崩溃恢复后不运行事务回滚。

  • 4 (SRV_FORCE_NO_IBUF_MERGE)

    阻止插入缓冲区合并操作。如果这些操作可能导致崩溃,则不执行。不计算表的统计信息。这个值可能会永久损坏数据文件。使用此值后,准备好删除并重新创建所有辅助索引。将InnoDB设置为只读。

  • 5 (SRV_FORCE_NO_UNDO_LOG_SCAN)

    在启动数据库时不查看撤销日志:InnoDB将即使是不完整的事务也视为已提交。这个值可能会永久损坏数据文件。将InnoDB设置为只读。

  • 6 (SRV_FORCE_NO_LOG_REDO)

    在恢复过程中不执行重做日志的前进。这个值可能会永久损坏数据文件。将数据库页面留在过时状态,这可能会导致 B 树和其他数据库结构出现更多损坏。将InnoDB设置为只读。

您可以从表中SELECT以导出它们。当innodb_force_recovery值为 3 或更低时,可以DROPCREATE表。当innodb_force_recovery值大于 3 时,也支持DROP TABLE。当innodb_force_recovery值大于 4 时,不允许DROP TABLE

如果您知道某个表在回滚时导致意外退出,您可以将其删除。如果遇到由于失败的大规模导入或ALTER TABLE导致的无限回滚,您可以终止mysqld进程,并将innodb_force_recovery设置为3,以在没有回滚的情况下启动数据库,然后DROP掉导致无限回滚的表。

如果表数据中的损坏阻止您转储整个表内容,带有ORDER BY *primary_key* DESC子句的查询可能能够转储受损部分之后的表部分。

如果需要较高的innodb_force_recovery值才能启动InnoDB,可能存在损坏的数据结构,可能导致复杂查询(包含WHEREORDER BY或其他子句的查询)失败。在这种情况下,您可能只能运行基本的SELECT * FROM t查询。

17.21.4 InnoDB 数据字典操作故障排除

原文:dev.mysql.com/doc/refman/8.0/en/innodb-troubleshooting-datadict.html

表定义信息存储在 InnoDB 数据字典中。如果移动数据文件,字典数据可能变得不一致。

如果数据字典损坏或一致性问题阻止您启动InnoDB,请参阅第 17.21.3 节,“强制 InnoDB 恢复”以获取有关手动恢复的信息。

无法打开数据文件

启用innodb_file_per_table(默认情况下),如果缺少 file-per-table 表空间文件(.ibd文件),则可能在启动时出现以下消息:

[ERROR] InnoDB: Operating system error number 2 in a file operation.
[ERROR] InnoDB: The error means the system cannot find the path specified.
[ERROR] InnoDB: Cannot open datafile for read-only: './test/t1.ibd' OS error: 71
[Warning] InnoDB: Ignoring tablespace `test/t1` because it could not be opened.

要解决这些消息,请发出DROP TABLE语句,以从数据字典中删除有关缺失表的数据。

恢复孤立的 file-per-table ibd 文件

该过程描述了如何将孤立的 file-per-table.ibd文件恢复到另一个 MySQL 实例。如果系统表空间丢失或无法恢复,并且您想要在新的 MySQL 实例上恢复.ibd文件备份,则可以使用此过程。

该过程不支持 general tablespace.ibd文件。

该过程假定您只有.ibd文件备份,您正在恢复到最初创建孤立的.ibd文件的 MySQL 版本,并且.ibd文件备份是干净的。有关创建干净备份的信息,请参阅第 17.6.1.4 节,“移动或复制 InnoDB 表”。

第 17.6.1.3 节,“导入 InnoDB 表”中概述的表导入限制适用于此过程。

  1. 在新的 MySQL 实例中,在同名数据库中重新创建表。

    mysql> CREATE DATABASE sakila;
    
    mysql> USE sakila;
    
    mysql> CREATE TABLE actor (
             actor_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
             first_name VARCHAR(45) NOT NULL,
             last_name VARCHAR(45) NOT NULL,
             last_update TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
             PRIMARY KEY  (actor_id),
             KEY idx_actor_last_name (last_name)
           )ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    
  2. 丢弃新创建表的表空间。

    mysql> ALTER TABLE sakila.actor DISCARD TABLESPACE;
    
  3. 将孤立的.ibd文件从备份目录复制到新的数据库目录。

    $> cp /backup_directory/actor.ibd *path/to/mysql-5.7/data*/sakila/
    
  4. 确保.ibd文件具有必要的文件权限。

  5. 导入孤立的.ibd文件。会发出警告,指示InnoDB正在尝试在没有模式验证的情况下导入文件。

    mysql> ALTER TABLE sakila.actor IMPORT TABLESPACE; SHOW WARNINGS;
    Query OK, 0 rows affected, 1 warning (0.15 sec)
    
    Warning | 1810 | InnoDB: IO Read error: (2, No such file or directory)
    Error opening './sakila/actor.cfg', will attempt to import
    without schema verification
    
  6. 查询表以验证.ibd文件是否成功恢复。

    mysql> SELECT COUNT(*) FROM sakila.actor;
    +----------+
    | count(*) |
    +----------+
    |      200 |
    +----------+
    

17.21.5 InnoDB 错误处理

原文:dev.mysql.com/doc/refman/8.0/en/innodb-error-handling.html

以下项目描述了InnoDB如何执行错误处理。InnoDB有时只回滚失败的语句,有时会回滚整个事务。

  • 如果在表空间中耗尽文件空间,则会发生 MySQL Table is full错误,并且InnoDB会回滚 SQL 语句。

  • 事务死锁会导致InnoDB回滚整个事务。发生这种情况时,请重试整个事务。

    锁等待超时会导致InnoDB回滚当前语句(等待锁并遇到超时的语句)。要使整个事务回滚,请启动服务器时启用--innodb-rollback-on-timeout。如果使用默认行为,请重试语句,或者如果启用了--innodb-rollback-on-timeout,则重试整个事务。

    在繁忙服务器上,死锁和锁等待超时是正常的,应用程序需要意识到它们可能发生,并通过重试来处理。通过在事务期间对数据进行第一次更改和提交之间尽可能少地进行工作,可以减少发生这些情况的可能性,从而锁定的时间最短,影响的行数最少。有时将工作分割到不同的事务中可能是实用和有帮助的。

  • 如果发生重复键错误,则回滚 SQL 语句,如果在语句中未指定IGNORE选项。

  • 行过长错误会回滚 SQL 语句。

  • 其他错误大多由 MySQL 代码层(在InnoDB存储引擎层之上)检测到,并回滚相应的 SQL 语句。在回滚单个 SQL 语句时不会释放锁。

在隐式回滚期间,以及在执行显式ROLLBACK SQL 语句期间,SHOW PROCESSLIST在相关连接的State列中显示Rolling back

17.22 InnoDB 限制

译文:dev.mysql.com/doc/refman/8.0/en/innodb-limits.html

本节描述了 InnoDB 表、索引、表空间以及 InnoDB 存储引擎的其他方面的限制。

  • 一张表最多可以包含 1017 列。虚拟生成列也包括在此限制内。

  • 一张表最多可以包含 64 个次要索引。

  • 对于使用 DYNAMICCOMPRESSED 行格式的 InnoDB 表,索引键前缀长度限制为 3072 字节。

    对于使用 REDUNDANTCOMPACT 行格式的 InnoDB 表,索引键前缀长度限制为 767 字节。例如,假设在 TEXTVARCHAR 列上使用了超过 191 个字符的 列前缀 索引,在 utf8mb4 字符集和每个字符最大 4 个字节的情况下,可能会达到这个限制。

    尝试使用超过限制的索引键前缀长度将返回错误。

    如果通过在创建 MySQL 实例时指定 innodb_page_size 选项将 InnoDB 页大小 降低为 8KB 或 4KB,那么基于 16KB 页大小的 3072 字节限制,索引键的最大长度将按比例降低。也就是说,当页大小为 8KB 时,最大索引键长度为 1536 字节,当页大小为 4KB 时,最大索引键长度为 768 字节。

    适用于索引键前缀的限制也适用于完整列索引键。

  • 最多允许为多列索引设置 16 列。超过限制将返回错误。

    ERROR 1070 (42000): Too many key parts specified; max 16 parts allowed
    
  • 行的最大大小,不包括存储在页外的任何可变长度列,对于 4KB、8KB、16KB 和 32KB 的页大小略小于半页。例如,默认的 innodb_page_size 为 16KB 时,最大行大小约为 8000 字节。然而,对于 64KB 的 InnoDB 页大小,最大行大小约为 16000 字节。LONGBLOBLONGTEXT 列必须小于 4GB,包括 BLOBTEXT 列在内的总行大小必须小于 4GB。

    如果一行长度小于半页,所有内容都存储在页面内。如果超过半页,变长列将选择外部离页存储,直到行适合半页为止,如第 17.11.2 节,“文件空间管理”中所述。

  • 尽管InnoDB内部支持大于 65535 字节的行大小,但 MySQL 本身对所有列的组合大小施加了 65535 的行大小限制。请参见第 10.4.7 节,“表列数和行大小限制”。

  • 在一些较旧的操作系统上,文件大小必须小于 2GB。这不是InnoDB的限制。如果您需要一个大的系统表空间,请使用多个较小的数据文件进行配置,而不是一个大的数据文件,或者将表数据分布在每个表一个文件和通用表空间数据文件中。

  • InnoDB日志文件的组合最大大小为 512GB。

  • 最小表空间大小略大于 10MB。最大表空间大小取决于InnoDB页面大小。

    表 17.31 InnoDB 最大表空间大小

    InnoDB 页面大小 最大表空间大小
    4KB 16TB
    8KB 32TB
    16KB 64TB
    32KB 128TB
    64KB 256TB

    最大表空间大小也是表的最大大小。

  • 一个InnoDB实例支持最多 2³²(4294967296)个表空间,其中少数表空间保留用于撤销和临时表。

  • 共享表空间支持最多 2³²(4294967296)个表。

  • 表空间文件的路径,包括文件名,在 Windows 上不能超过MAX_PATH限制。在 Windows 10 之前,MAX_PATH限制为 260 个字符。从 Windows 10,版本 1607 开始,MAX_PATH限制已从常见的 Win32 文件和目录函数中移除,但您必须启用新的行为。

  • 有关并发读写事务相关的限制,请参见第 17.6.6 节,“撤销日志”。

17.23 InnoDB 限制和限制

原文:dev.mysql.com/doc/refman/8.0/en/innodb-restrictions-limitations.html

本节描述了 InnoDB 存储引擎的限制和限制。

  • 不能创建具有与内部 InnoDB 列名匹配的列名的表(包括 DB_ROW_IDDB_TRX_IDDB_ROLL_PTR)。此限制适用于任何大小写形式中的名称使用。

    mysql> CREATE TABLE t1 (c1 INT, db_row_id INT) ENGINE=INNODB;
    ERROR 1166 (42000): Incorrect column name 'db_row_id'
    
  • SHOW TABLE STATUS 对于 InnoDB 表不提供准确的统计信息,除了表保留的物理大小。行计数仅是 SQL 优化中使用的粗略估计。

  • InnoDB 不会保留表中行的内部计数,因为并发事务可能在同一时间“看到”不同数量的行。因此,SELECT COUNT(*) 语句仅计算当前事务可见的行数。

    有关 InnoDB 如何处理 SELECT COUNT(*) 语句的信息,请参阅 第 14.19.1 节,“聚合函数描述” 中的 COUNT() 描述。

  • ROW_FORMAT=COMPRESSED 不支持大于 16KB 的页面大小。

  • 使用特定 InnoDB 页面大小(innodb_page_size)的 MySQL 实例不能使用来自使用不同页面大小的实例的数据文件或日志文件。

  • 有关使用 可传输表空间 功能导入表的限制,请参见 表导入限制。

  • 有关在线 DDL 的限制,请参见 第 17.12.8 节,“在线 DDL 限制”。

  • 有关一般表空间的限制,请参见 一般表空间限制。

  • 有关数据静态加密的限制,请参见 加密限制。

第十八章 备选存储引擎

原文:dev.mysql.com/doc/refman/8.0/en/storage-engines.html

目录

18.1 设置存储引擎

18.2 MyISAM 存储引擎

18.2.1 MyISAM 启动选项

18.2.2 键所需的空间

18.2.3 MyISAM 表存储格式

18.2.4 MyISAM 表问题

18.3 MEMORY 存储引擎

18.4 CSV 存储引擎

18.4.1 修复和检查 CSV 表

18.4.2 CSV 限制

18.5 ARCHIVE 存储引擎

18.6 BLACKHOLE 存储引擎

18.7 MERGE 存储引擎

18.7.1 MERGE 表优缺点

18.7.2 MERGE 表问题

18.8 FEDERATED 存储引擎

18.8.1 FEDERATED 存储引擎概述

18.8.2 如何创建 FEDERATED 表

18.8.3 FEDERATED 存储引擎注意事项和提示

18.8.4 FEDERATED 存储引擎资源

18.9 EXAMPLE 存储引擎

18.10 其他存储引擎

18.11 MySQL 存储引擎架构概述

18.11.1 可插拔存储引擎架构

18.11.2 通用数据库服务器层

存储引擎是 MySQL 组件,用于处理不同表类型的 SQL 操作。InnoDB 是默认和最通用的存储引擎,Oracle 建议除了专用用例外,都使用它来创建表。(在 MySQL 8.0 中,CREATE TABLE 语句默认创建 InnoDB 表。)

MySQL 服务器使用可插拔存储引擎架构,允许存储引擎在运行中加载和卸载。

要确定服务器支持哪些存储引擎,请使用 SHOW ENGINES 语句。Support 列中的值指示引擎是否可用。YESNODEFAULT 的值表示引擎可用、不可用或可用且当前设置为默认存储引擎。

mysql> SHOW ENGINES\G
*************************** 1\. row ***************************
      Engine: PERFORMANCE_SCHEMA
     Support: YES
     Comment: Performance Schema
Transactions: NO
          XA: NO
  Savepoints: NO
*************************** 2\. row ***************************
      Engine: InnoDB
     Support: DEFAULT
     Comment: Supports transactions, row-level locking, and foreign keys
Transactions: YES
          XA: YES
  Savepoints: YES
*************************** 3\. row ***************************
      Engine: MRG_MYISAM
     Support: YES
     Comment: Collection of identical MyISAM tables
Transactions: NO
          XA: NO
  Savepoints: NO
*************************** 4\. row ***************************
      Engine: BLACKHOLE
     Support: YES
     Comment: /dev/null storage engine (anything you write to it disappears)
Transactions: NO
          XA: NO
  Savepoints: NO
*************************** 5\. row ***************************
      Engine: MyISAM
     Support: YES
     Comment: MyISAM storage engine
Transactions: NO
          XA: NO
  Savepoints: NO
...

本章涵盖了特定用途的 MySQL 存储引擎的使用案例。它不涵盖默认的 InnoDB 存储引擎或 NDB 存储引擎,这些在 Chapter 17, The InnoDB Storage Engine 和 Chapter 25, MySQL NDB Cluster 8.0 中有介绍。对于高级用户,它还包含了可插拔存储引擎架构的描述(请参见 Section 18.11, “Overview of MySQL Storage Engine Architecture”)。

有关商业 MySQL Server 二进制版本提供的功能信息,请访问 MySQL 网站上的MySQL Editions。可用的存储引擎可能取决于您使用的 MySQL 版本。

关于 MySQL 存储引擎常见问题的答案,请参见 Section A.2, “MySQL 8.0 FAQ: Storage Engines”。

MySQL 8.0 支持的存储引擎

  • InnoDB:MySQL 8.0 中的默认存储引擎。InnoDB 是 MySQL 的事务安全(ACID 兼容)存储引擎,具有提交、回滚和崩溃恢复功能,以保护用户数据。InnoDB 行级锁定(不升级为更粗粒度的锁)和 Oracle 风格的一致性非锁定读取增加了多用户并发性和性能。InnoDB 将用户数据存储在聚集索引中,以减少基于主键的常见查询的 I/O。为了保持数据完整性,InnoDB 还支持 FOREIGN KEY 外键完整性约束。有关 InnoDB 的更多信息,请参见 Chapter 17, The InnoDB Storage Engine

  • MyISAM:这些表占用空间小。表级锁定 限制了读/写工作负载的性能,因此通常用于 Web 和数据仓库配置中的只读或读多写少的工作负载。

  • Memory:将所有数据存储在 RAM 中,用于快速访问需要快速查找非关键数据的环境。这个引擎以前被称为 HEAP 引擎。它的使用案例正在减少;InnoDB 通过其缓冲池内存区提供了一种通用且耐用的方式来将大部分或全部数据保存在内存中,而 NDBCLUSTER 为庞大的分布式数据集提供了快速的键值查找。

  • CSV:它的表实际上是带有逗号分隔值的文本文件。CSV 表允许你以 CSV 格式导入或导出数据,与读写相同格式的脚本和应用程序交换数据。因为 CSV 表没有索引,通常在正常操作期间将数据保存在InnoDB表中,仅在导入或导出阶段使用 CSV 表。

  • 归档:这些紧凑的、无索引的表用于存储和检索大量很少被引用的历史、归档或安全审计信息。

  • 黑洞:黑洞存储引擎接受但不存储数据,类似于 Unix 的/dev/null设备。查询总是返回一个空集。这些表可以在复制配置中使用,其中 DML 语句被发送到副本服务器,但源服务器不保留自己的数据副本。

  • NDB(也称为NDBCLUSTER):这个集群数据库引擎特别适用于需要最高可用性和可用性的应用程序。

  • 合并:使 MySQL DBA 或开发人员可以逻辑地将一系列相同的MyISAM表分组,并将它们引用为一个对象。适用于数据仓库等 VLDB 环境。

  • 联合:提供了将不同的 MySQL 服务器链接起来,从许多物理服务器创建一个逻辑数据库的能力。非常适合分布式或数据仓库环境。

  • 示例:这个引擎在 MySQL 源代码中作为一个示例,展示了如何开始编写新的存储引擎。主要是为开发人员感兴趣。这个存储引擎是一个“存根”,什么也不做。你可以用这个引擎创建表,但不能在其中存储或检索数据。

你不必限制整个服务器或模式使用相同的存储引擎。你可以为任何表指定存储引擎。例如,一个应用程序可能主要使用InnoDB表,其中一个CSV表用于将数据导出到电子表格,以及一些MEMORY表用于临时工作空间。

选择存储引擎

MySQL 提供的各种存储引擎是针对不同用例设计的。以下表格提供了一些 MySQL 提供的存储引擎的概述,表格后面跟着澄清说明。

表 18.1 存储引擎特性摘要

特性 MyISAM Memory InnoDB Archive NDB
B-tree 索引
备份/时间点恢复(注 1)
集群数据库支持
聚集索引
压缩数据 是(注 2)
数据缓存 不适用
加密数据 是(注 3) 是(注 3) 是(注 4) 是(注 3) 是(注 5)
外键支持
全文搜索索引 是(注 6)
地理空间数据类型支持
地理空间索引支持 是(注 7)
哈希索引 否(注 8)
索引缓存 不适用
锁定粒度
MVCC
复制支持(注 1) 有限(注 9)
存储限制 256TB RAM 64TB 384EB
T 树索引
事务
更新数据字典的统计信息
特性 MyISAM Memory InnoDB Archive NDB

注:

1. 在服务器端实现,而不是在存储引擎中。

2. 仅当使用压缩行格式时,支持压缩的 MyISAM 表。使用压缩行格式的 MyISAM 表是只读的。

3. 通过加密函数在服务器端实现。

4. 通过加密函数在服务器端实现;在 MySQL 5.7 及更高版本中,支持数据静态加密。

5. 通过加密函数在服务器端实现;NDB 8.0.22 起支持加密的 NDB 备份;NDB 8.0.29 及更高版本支持透明的 NDB 文件系统加密。

6. MySQL 5.6 及更高版本支持全文索引。

7. MySQL 5.7 及更高版本支持地理空间索引。

8. InnoDB 在内部利用哈希索引来实现其自适应哈希索引功能。

9. 请参见本节后面的讨论。

18.1 设置存储引擎

原文:dev.mysql.com/doc/refman/8.0/en/storage-engine-setting.html

当您创建新表时,可以通过在CREATE TABLE语句中添加ENGINE表选项来指定要使用的存储引擎:

-- ENGINE=INNODB not needed unless you have set a different
-- default storage engine.
CREATE TABLE t1 (i INT) ENGINE = INNODB;
-- Simple table definitions can be switched from one to another.
CREATE TABLE t2 (i INT) ENGINE = CSV;
CREATE TABLE t3 (i INT) ENGINE = MEMORY;

当您省略ENGINE选项时,将使用默认存储引擎。在 MySQL 8.0 中,默认引擎是InnoDB。您可以通过使用--default-storage-engine服务器启动选项或通过在my.cnf配置文件中设置default-storage-engine选项来指定默认引擎。

您可以通过设置default_storage_engine变量为当前会话设置默认存储引擎:

SET default_storage_engine=NDBCLUSTER;

使用CREATE TEMPORARY TABLE创建的TEMPORARY表的存储引擎可以通过在启动时或运行时设置default_tmp_storage_engine来单独设置,与永久表的引擎不同。

要将表从一种存储引擎转换为另一种,使用指示新引擎的ALTER TABLE语句:

ALTER TABLE t ENGINE = InnoDB;

参见第 15.1.20 节,“CREATE TABLE Statement”和第 15.1.9 节,“ALTER TABLE Statement”。

如果您尝试使用未编译或已编译但已停用的存储引擎,MySQL 会使用默认存储引擎创建表。例如,在复制设置中,也许您的源服务器使用InnoDB表以获得最大安全性,但副本服务器使用其他存储引擎以换取速度而牺牲耐久性或并发性。

默认情况下,当CREATE TABLEALTER TABLE无法使用默认存储引擎时会生成警告。为了防止混淆和意外行为,如果所需引擎不可用,请启用NO_ENGINE_SUBSTITUTION SQL 模式。如果所需引擎不可用,此设置会产生错误而不是警告,并且表不会被创建或更改。参见第 7.1.11 节,“服务器 SQL 模式”。

MySQL 可能会根据存储引擎的不同,将表的索引和数据存储在一个或多个其他文件中。表和列的定义存储在 MySQL 数据字典中。各个存储引擎会为其管理的表创建所需的任何额外文件。如果表名包含特殊字符,则表文件的名称会包含这些字符的编码版本,如 Section 11.2.4,“标识符映射到文件名”中所述。

18.2 MyISAM 存储引擎

原文:dev.mysql.com/doc/refman/8.0/en/myisam-storage-engine.html

18.2.1 MyISAM 启动选项

18.2.2 键所需的空间

18.2.3 MyISAM 表存储格式

18.2.4 MyISAM 表问题

MyISAM基于旧的(不再可用)ISAM存储引擎,但具有许多有用的扩展。

表 18.2 MyISAM 存储引擎特性

功能 支持
B 树索引
备份/时间点恢复(在服务器中实现,而不是在存储引擎中。)
集群数据库支持
聚集索引
压缩数据 是(仅在使用压缩行格式时支持压缩的 MyISAM 表。使用压缩行格式和 MyISAM 的表是只读的。)
数据缓存
加密数据 是(通过加密函数在服务器中实现。)
外键支持
全文搜索索引
地理空间数据类型支持
地理空间索引支持
哈希索引
索引缓存
锁定粒度
MVCC
复制支持(在服务器中实现,而不是在存储引擎中。)
存储限制 256TB
T 树索引
事务
更新数据字典的统计信息
功能 支持

每个MyISAM表在磁盘上以两个文件存储。这些文件的名称以表名开头,并具有指示文件类型的扩展名。数据文件具有.MYDMYData)扩展名。索引文件具有.MYIMYIndex)扩展名。表定义存储在 MySQL 数据字典中。

要明确指定要使用MyISAM表,可以使用ENGINE表选项指示:

CREATE TABLE t (i INT) ENGINE = MYISAM;

在 MySQL 8.0 中,通常需要使用ENGINE来指定MyISAM存储引擎,因为InnoDB是默认引擎。

您可以使用mysqlcheck客户端或myisamchk实用程序检查或修复MyISAM表。您还可以使用myisampack压缩MyISAM表,以占用更少的空间。请参阅 Section 6.5.3, “mysqlcheck — A Table Maintenance Program”,Section 6.6.4, “myisamchk — MyISAM Table-Maintenance Utility”和 Section 6.6.6, “myisampack — Generate Compressed, Read-Only MyISAM Tables”。

在 MySQL 8.0 中,MyISAM存储引擎不提供分区支持。在以前的 MySQL 版本中创建的分区MyISAM表无法在 MySQL 8.0 中使用。有关更多信息,请参见第 26.6.2 节,“与存储引擎相关的分区限制”。有关升级这些表以便在 MySQL 8.0 中使用的帮助,请参见第 3.5 节,“MySQL 8.0 中的更改”。

MyISAM表具有以下特点:

  • 所有数据值都以低字节优先存储。这使得数据与机器和操作系统无关。对于二进制可移植性的唯一要求是机器使用二进制补码有符号整数和 IEEE 浮点格式。这些要求在主流机器中被广泛使用。二进制兼容性可能不适用于有时具有特殊处理器的嵌入式系统。

    以低字节优先存储数据不会带来显著的速度惩罚;表行中的字节通常是不对齐的,读取不对齐字节按顺序比按相反顺序需要更少的处理。此外,服务器中提取列值的代码与其他代码相比并不是时间关键。

  • 所有数值键值都以高字节优先存储,以便更好地压缩索引。

  • 支持大文件(最多 63 位文件长度)的文件系统和操作系统。

  • MyISAM表中最多有(2³²)²(1.844E+19)行。

  • 每个MyISAM表的最大索引数为 64。

    每个索引的最大列数为 16。

  • 最大键长度为 1000 字节。这可以通过更改源代码并重新编译来改变。对于长度超过 250 字节的键,使用比默认的 1024 字节更大的键块大小。

  • 当按排序顺序插入行时(例如使用AUTO_INCREMENT列时),索引树会分裂,使高节点仅包含一个键。这提高了索引树的空间利用率。

  • 每个表支持一个AUTO_INCREMENT列的内部处理。MyISAM自动更新此列的INSERTUPDATE操作。这使得AUTO_INCREMENT列更快(至少快 10%)。在删除后,顺序顶部的值不会被重用。(当AUTO_INCREMENT列被定义为多列索引的最后一列时,从顺序顶部删除的值会被重用。)AUTO_INCREMENT值可以通过ALTER TABLEmyisamchk重置。

  • 在混合删除、更新和插入时,动态大小的行碎片化较少。这是通过自动组合相邻的已删除块和在下一个块被删除时扩展块来完成的。

  • MyISAM支持并发插入:如果表在数据文件中间没有空闲块,您可以在其他线程从表中读取数据的同时向其插入新行。空闲块可能是由于删除行或更新动态长度行而导致的,其数据超过当前内容。当所有空闲块都被使用完(填满)时,未来的插入操作再次变得并发。参见 Section 10.11.3, “Concurrent Inserts”。

  • 将数据文件和索引文件放在不同的目录中,放在不同的物理设备上,可以通过DATA DIRECTORYINDEX DIRECTORY表选项来加快速度,CREATE TABLE。参见 Section 15.1.20, “CREATE TABLE Statement”。

  • BLOBTEXT列可以建立索引。

  • 索引列中允许存在NULL值。每个键占用 0 到 1 个字节。

  • 每个字符列可以有不同的字符集。参见 Chapter 12, Character Sets, Collations, Unicode

  • MyISAM索引文件中有一个标志,指示表是否正确关闭。如果使用myisam_recover_options系统变量启动mysqld,则在打开时会自动检查MyISAM表,并在表未正确关闭时进行修复。

  • myisamchk如果使用--update-state选项运行,则会标记表为已检查。myisamchk --fast仅检查那些没有此标记的表。

  • myisamchk --analyze存储部分键的统计信息,以及整个键的统计信息。

  • myisampack可以压缩BLOBVARCHAR列。

MyISAM还支持以下功能:

  • 支持真正的VARCHAR类型;VARCHAR列以一个或两个字节存储的长度开始。

  • 带有VARCHAR列的表可能具有固定或动态行长度。

  • 表中VARCHARCHAR列的长度之和可以达到 64KB。

  • 任意长度的UNIQUE约束。

附加资源

18.2.1 MyISAM 启动选项

原文:dev.mysql.com/doc/refman/8.0/en/myisam-start.html

下列选项可用于更改MyISAM表的行为。有关更多信息,请参见mysqld的第 7.1.7 节,“服务器命令选项”。

表 18.3 MyISAM 选项和变量参考

名称 命令行 选项文件 系统变量 状态变量 变量范围 动态
bulk_insert_buffer_size 两者
concurrent_insert 全局
delay_key_write 全局
have_rtree_keys 全局
key_buffer_size 全局
log-isam
myisam-block-size
myisam_data_pointer_size 全局
myisam_max_sort_file_size 全局
myisam_mmap_size 全局
myisam_recover_options 全局
myisam_repair_threads 两者
myisam_sort_buffer_size 两者
myisam_stats_method 两者
myisam_use_mmap 全局
tmp_table_size 两者
名称 命令行 选项文件 系统变量 状态变量 变量范围 动态

下列系统变量影响MyISAM表的行为。有关更多信息,请参见第 7.1.8 节,“服务器系统变量”。

  • bulk_insert_buffer_size

    用于批量插入优化中使用的树缓存大小。

    这是每个线程的限制!

  • delay_key_write=ALL

    在任何MyISAM表的写入之间不要刷新键缓冲区。

    如果这样做,您不应该从另一个程序(例如从另一个 MySQL 服务器或使用myisamchk)访问MyISAM表格,当表格正在使用时。这样做会导致索引损坏。使用--external-locking并不能消除这种风险。

  • myisam_max_sort_file_size

    MySQL 在重新创建MyISAM索引时允许使用的临时文件的最大大小(在REPAIR TABLEALTER TABLELOAD DATA期间)。如果文件大小大于此值,则使用键缓存而不是创建索引,这会更慢。该值以字节为单位给出。

  • myisam_recover_options=*mode*

    设置自动恢复崩溃的MyISAM表的模式。

  • myisam_sort_buffer_size

    设置在恢复表格时使用的缓冲区的大小。

如果您使用设置了myisam_recover_options系统变量的值启动mysqld,则自动恢复将被激活。在这种情况下,当服务器打开MyISAM表时,它会检查表是否标记为崩溃,或者表的打开计数变量不为 0 且您正在以禁用外部锁定的方式运行服务器。如果这两个条件中的任何一个为真,则会发生以下情况:

  • 服务器检查表格是否有错误。

  • 如果服务器发现错误,则尝试进行快速表修复(带排序但不重新创建数据文件)。

  • 如果由于数据文件中的错误(例如重复键错误)而导致修复失败,则服务器会再次尝试,这次重新创建数据文��。

  • 如果修复仍然失败,服务器会再次尝试使用旧的修复选项方法(逐行写入而不排序)。这种方法应该能够修复任何类型的错误,并且对磁盘空间要求低。

如果恢复无法从先前完成的语句中恢复所有行,并且您没有在myisam_recover_options系统变量的值中指定FORCE,则自动修复将在错误日志中中止并显示错误消息:

Error: Couldn't repair table: test.g00pages

如果您指定了FORCE,则会写入类似于以下的警告:

Warning: Found 344 of 354 rows when repairing ./test/g00pages

如果自动恢复值包括BACKUP,则恢复过程会创建形如*tbl_name-datetime*.BAK的文件。您应该有一个cron脚本,自动将这些文件从数据库目录移动到备份介质。

18.2.2 键所需的空间

原文:dev.mysql.com/doc/refman/8.0/en/key-space.html

MyISAM 表使用 B 树索引。您可以粗略计算索引文件的大小为 (key_length+4)/0.67,对所有键求和。这是最坏情况下的情况,当所有键按排序顺序插入时,表中没有任何压缩键。

字符串索引是空间压缩的。如果第一个索引部分是字符串,则也进行前缀压缩。空间压缩使索引文件比最坏情况下的数字小,如果字符串列有很多尾随空格或是一个VARCHAR 列,没有始终使用到完整长度。前缀压缩用于以字符串开头的键。前缀压缩有助于处理具有相同前缀的许多字符串。

MyISAM 表中,您还可以通过在创建表时指定 PACK_KEYS=1 表选项来对数字进行前缀压缩。数字以高字节优先存储,因此当您有许多整数键具有相同前缀时,这很有帮助。

18.2.3 MyISAM 表存储格式

原文:dev.mysql.com/doc/refman/8.0/en/myisam-table-formats.html

18.2.3.1 静态(固定长度)表特性

18.2.3.2 动态表特性

18.2.3.3 压缩表特性

MyISAM支持三种不同的存储格式。其中两种,固定和动态格式,根据你使用的列类型自动选择。第三种,压缩格式,只能使用myisampack实用程序创建(参见第 6.6.6 节,“myisampack — 生成压缩的只读 MyISAM 表”)。

当你使用CREATE TABLEALTER TABLE创建没有BLOBTEXT列的表时,可以使用ROW_FORMAT表选项强制表格式为FIXEDDYNAMIC

查看第 15.1.20 节,“CREATE TABLE 语句”,了解ROW_FORMAT的信息。

你可以使用myisamchk--unpack选项来解压缩MyISAM表;查看第 6.6.4 节,“myisamchk — MyISAM 表维护实用程序”获取更多信息。

原文:dev.mysql.com/doc/refman/8.0/en/static-format.html

18.2.3.1 静态(固定长度)表特性

静态格式是MyISAM表的默认格式。当表中不包含可变长度列(VARCHARVARBINARYBLOBTEXT)时使用。每行使用固定字节数存储。

在三种MyISAM存储格式中,静态格式是最简单和最安全(最不容易损坏)的。由于在磁盘上很容易找到数据文件中的行,它也是磁盘上最快的格式:根据索引中的行号查找行时,将行号乘以行长度以计算行位置。此外,在扫描表时,每次磁盘读取操作都可以很容易地读取恒定数量的行。

如果在 MySQL 服务器写入固定格式的MyISAM文件时计算机崩溃,安全性得到证明。在这种情况下,myisamchk可以轻松确定每行的起始和结束位置,因此通常可以回收除部分写入的行之外的所有行。MyISAM表索引始终可以根据数据行重建。

注意

仅适用于没有BLOBTEXT列的表的固定长度行格式。创建具有此类列的表并使用显式的ROW_FORMAT子句不会引发错误或警告;格式规范将被忽略。

静态格式表具有以下特点:

  • CHARVARCHAR列会被填充到指定的列宽,尽管列类型不会改变。BINARYVARBINARY列会用0x00字节填充到列宽。

  • NULL列需要额外的空间来记录它们的值是否为NULL。每个NULL列额外占用一位,向最近的字节取整。

  • 非常快速。

  • 易于缓存。

  • 在崩溃后易于重建,因为行位于固定位置。

  • 除非删除大量行并希望将空闲磁盘空间返回给操作系统,否则不需要重新组织。要执行此操作,请使用OPTIMIZE TABLEmyisamchk -r

  • 通常需要比动态格式表更多的磁盘空间。

  • 静态大小行的预期行长度(以字节为单位)通过以下表达式计算:

    row length = 1
                 + (*sum of column lengths*)
                 + (*number of NULL columns* + *delete_flag* + 7)/8
                 + (*number of variable-length columns*)
    

    delete_flag 在静态行格式的表中为 1。静态表在行记录中使用一个位来表示行是否已被删除。对于动态表,delete_flag 为 0,因为标志位存储在动态行头中。

原文:dev.mysql.com/doc/refman/8.0/en/dynamic-format.html

18.2.3.2 动态表特性

如果MyISAM表包含任何可变长度列(VARCHARVARBINARYBLOBTEXT),或者表是使用ROW_FORMAT=DYNAMIC表选项创建的,则使用动态存储格式。

动态格式比静态格式稍微复杂,因为每行都有一个标头,指示其长度。当由于更新而使行变长时,行可能会变得碎片化(存储在非连续的片段中)。

您可以使用OPTIMIZE TABLEmyisamchk -r来对表进行碎片整理。如果您在一个表中频繁访问或更改固定长度列,并且该表还包含一些可变长度列,那么将可变长度列移动到其他表中以避免碎片化可能是一个好主意。

动态格式表具有以下特点:

  • 所有字符串列都是动态的,除了长度小于四的列。

  • 每行前面都有一个位图,指示哪些列包含空字符串(对于字符串列)或零(对于数值列)。这不包括包含NULL值的列。如果字符串列在去除尾随空格后长度为零,或者数值列的值为零,则在位图中标记并不保存到磁盘。非空字符串保存为长度字节加上字符串内容。

  • NULL列需要额外的空间来记录它们的值是否为NULL。每个NULL列额外占用一位,向上取整到最近的字节。

  • 比固定长度表通常需要更少的磁盘空间。

  • 每行只使用所需的空间。但是,如果一行变得更大,它将被分成所需的碎片,导致行碎片化。例如,如果更新了一行的信息,使行长度增加,那么该行将变得碎片化。在这种情况下,您可能需要定期运行OPTIMIZE TABLEmyisamchk -r来提高性能。使用myisamchk -ei获取表统计信息。

  • 在崩溃后更难重建比静态格式表,因为行可能会分成许多片段,而且链接(片段)可能丢失。

  • 动态大小行的预期行长度使用以下表达式计算:

    3
    + (*number of columns* + 7) / 8
    + (*number of char columns*)
    + (*packed size of numeric columns*)
    + (*length of strings*)
    + (*number of NULL columns* + 7) / 8
    

    每个链接都会有 6 个字节的惩罚。每当更新导致行的扩大时,就会链接一个动态行。每个新链接至少有 20 个字节,所以下一个扩大可能会放在同一个链接中。如果不是,就会创建另一个链接。你可以使用myisamchk -ed来查找链接的数量。所有链接可以通过OPTIMIZE TABLEmyisamchk -r来移除。

原文:dev.mysql.com/doc/refman/8.0/en/compressed-format.html

18.2.3.3 压缩表特性

压缩存储格式是使用myisampack工具生成的只读格式。压缩表可以使用myisamchk解压缩。

压缩表具有以下特性:

  • 压缩表占用非常少的磁盘空间。这最小化了磁盘使用,对于使用慢速磁盘(如 CD-ROM)很有帮助。

  • 每行都单独压缩,因此几乎没有访问开销。每行的标头占用一到三个字节,取决于表中最大的行。每列的压缩方式不同。通常每列都有不同的哈夫曼树。一些压缩类型包括:

    • 后缀空间压缩。

    • 前缀空间压缩。

    • 值为零的数字使用一位存储。

    • 如果整数列中的值范围较小,则使用可能的最小类型存储该列。例如,一个BIGINT列(八个字节)可以存储为一个TINYINT列(一个字节),如果其所有值都在 -128127 的范围内。

    • 如果一列只有一小组可能的值,数据类型将转换为ENUM

    • 一列可以使用前述压缩类型的任意组合。

  • 可用于固定长度或动态长度行。

注意

虽然压缩表是只读的,因此您不能更新或添加表中的行,但 DDL(数据定义语言)操作仍然有效。例如,您仍然可以使用DROP删除表,使用TRUNCATE TABLE清空表。

18.2.4 MyISAM 表格问题

原文:dev.mysql.com/doc/refman/8.0/en/myisam-table-problems.html

18.2.4.1 损坏的 MyISAM 表格

18.2.4.2 未正确关闭表格导致的问题

MySQL 用于存储数据的文件格式经过了广泛测试,但总会有一些情况可能导致数据库表损坏。以下讨论描述了这种情况可能发生的原因以及如何处理。

原文:dev.mysql.com/doc/refman/8.0/en/corrupted-myisam-tables.html

18.2.4.1 损坏的 MyISAM 表

即使MyISAM表格式非常可靠(由 SQL 语句对表所做的所有更改都在语句返回之前写入),如果发生以下任何事件,仍然可能出现损坏的表:

  • mysqld进程在写入过程中被终止。

  • 发生意外的计算机关闭(例如,计算机被关闭)。

  • 硬件故障。

  • 您正在使用外部程序(例如myisamchk)同时修改服务器正在修改的表。

  • MySQL 或MyISAM代码中的软件错误。

损坏表的典型症状包括:

  • 从表中选择数据时出现以下错误:

    Incorrect key file for table: '...'. Try to repair it
    
  • 查询在表中找不到行或返回不完整的结果。

您可以使用CHECK TABLE语句检查MyISAM表的健康状况,并使用REPAIR TABLE修复损坏的MyISAM表。当mysqld未运行时,您还可以使用myisamchk命令检查或修复表。请参阅第 15.7.3.2 节,“CHECK TABLE Statement”,第 15.7.3.5 节,“REPAIR TABLE Statement”,以及第 6.6.4 节,“myisamchk — MyISAM 表维护实用程序”。

如果您的表经常损坏,您应该尝试确定为什么会发生这种情况。最重要的是要知道表是否因意外服务器退出而损坏。您可以通过查看错误日志中最近的重新启动的 mysqld消息来轻松验证这一点。如果有这样的消息,那么表损坏很可能是服务器死机的结果。否则,损坏可能发生在正常操作期间。这是一个错误。您应该尝试创建一个可重现的测试用例来演示问题。请参阅第 B.3.3.3 节,“如果 MySQL 一直崩溃该怎么办”,以及第 7.9 节,“调试 MySQL”。

posted @ 2024-06-23 12:23  绝不原创的飞龙  阅读(16)  评论(0编辑  收藏  举报