#### 8.12.3.1 MySQL 如何使用内存

[](<>)

MySQL 分配缓冲区和缓存以提高数据库操作的性能。默认配置旨在允许 MySQL 服务器在具有大约 512MB RAM 的虚拟机上启动。您可以通过增加某些缓存和缓冲区相关系统变量的值来提高 MySQL 性能。您还可以修改默认配置以在内存有限的系统上运行 MySQL。

下面的列表描述了 MySQL 使用内存的一些方式。在适用的情况下，引用了相关的系统变量。有些项目是存储引擎或特定于功能的。

-   这`InnoDB`缓冲池是保存缓存的内存区域`InnoDB`表、索引和其他辅助缓冲区的数据。为了大容量读取操作的效率，缓冲池被划分为[页面](glossary.html#glos_page)可能包含多行。为了缓存管理的效率，缓冲池被实现为页链表；很少使用的数据在缓存中老化，使用的变体[LRU](glossary.html#glos_lru)算法。有关详细信息，请参阅[第 15.5.1 节，“缓冲池”](innodb-buffer-pool.html).

    缓冲池的大小对系统性能很重要：

    -   `InnoDB`在服务器启动时为整个缓冲池分配内存，使用`malloc()`操作。这[`innodb_buffer_pool_size`](innodb-parameters.html#sysvar_innodb_buffer_pool_size)系统变量定义缓冲池大小。通常，推荐[`innodb_buffer_pool_size`](innodb-parameters.html#sysvar_innodb_buffer_pool_size)值是系统内存的 50% 到 75%。[`innodb_buffer_pool_size`](innodb-parameters.html#sysvar_innodb_buffer_pool_size)可以在服务器运行时动态配置。有关详细信息，请参阅[第 15.8.3.1 节，“配置 InnoDB 缓冲池大小”](innodb-buffer-pool-resize.html).

    -   在具有大量内存的系统上，可以通过将缓冲池划分为多个[缓冲池实例](glossary.html#glos_buffer_pool_instance).这[`innodb_buffer_pool_instances`](innodb-parameters.html#sysvar_innodb_buffer_pool_instances)系统变量定义缓冲池实例的数量。

    -   太小的缓冲池可能会导致过度搅动，因为页面从缓冲池中刷新，只是在短时间内再次需要。

    -   过大的缓冲池可能会因为内存竞争而导致交换。

-   存储引擎接口使优化器能够提供有关记录缓冲区大小的信息，以用于优化器估计可能读取多行的扫描。缓冲区大小可以根据估计的大小而变化。`InnoDB`使用这种可变大小的缓冲功能来利用行预取，并减少锁存和 B 树导航的开销。

-   所有线程共享[`MyISAM`](myisam-storage-engine.html)密钥缓冲区。这[`key_buffer_size`](server-system-variables.html#sysvar_key_buffer_size)系统变量决定了它的大小。

    对于每个`MyISAM`服务器打开的表，索引文件打开一次；对于访问该表的每个并发运行的线程，数据文件打开一次。对于每个并发线程，一个表结构，每列的列结构，以及一个大小的缓冲区`3 * *`ñ`*`被分配（其中*`ñ`*是最大行长，不算[`斑点`](blob.html)列）。一种[`斑点`](blob.html)列需要五到八个字节加上长度[`斑点`](blob.html)数据。这`MyISAM`存储引擎维护一个额外的行缓冲区供内部使用。

-   这[`myisam_use_mmap`](server-system-variables.html#sysvar_myisam_use_mmap)系统变量可以设置为 1 以启用所有内存映射`MyISAM`表。

-   如果内部内存临时表变得太大（如使用[`tmp_table_size`](server-system-variables.html#sysvar_tmp_table_size)和[`max_heap_table_size`](server-system-variables.html#sysvar_max_heap_table_size)系统变量），MySQL 自动将表从内存格式转换为磁盘格式。从 MySQL 8.0.16 开始，磁盘上的临时表始终使用 InnoDB 存储引擎。（以前，为此目的使用的存储引擎是由[`internal_tmp_disk_storage_engine`](server-system-variables.html#sysvar_internal_tmp_disk_storage_engine)系统变量，不再支持。）您可以增加允许的临时表大小，如中所述[第 8.4.4 节，“MySQL 中的内部临时表使用”](internal-temporary-tables.html).

    为了[`记忆`](memory-storage-engine.html)显式创建的表[`创建表`](create-table.html)， 只有[`max_heap_table_size`](server-system-variables.html#sysvar_max_heap_table_size)系统变量决定了一个表可以增长多大，并且没有转换为磁盘格式。

-   这[MySQL 性能模式](performance-schema.html)是用于在低级别监视 MySQL 服务器执行的功能。性能模式以增量方式动态分配内存，将其内存使用扩展到实际的服务器负载，而不是在服务器启动期间分配所需的内存。分配内存后，在服务器重新启动之前不会释放它。有关详细信息，请参阅[第 27.17 节，“性能模式内存分配模型”](performance-schema-memory-model.html).

-   服务器用来管理客户端连接的每个线程都需要一些特定于线程的空间。以下列表指示这些以及哪些系统变量控制它们的大小：

    -   一个堆栈（[`线程堆栈`](server-system-variables.html#sysvar_thread_stack))

    -   一个连接缓冲区（[`net_buffer_length`](server-system-variables.html#sysvar_net_buffer_length))

    -   结果缓冲区（[`net_buffer_length`](server-system-variables.html#sysvar_net_buffer_length))

        连接缓冲区和结果缓冲区都以大小等于[`net_buffer_length`](server-system-variables.html#sysvar_net_buffer_length)字节，但动态放大到[`max_allowed_pa​​cket`](server-system-variables.html#sysvar_max_allowed_packet)字节根据需要。结果缓冲区缩小到[`net_buffer_length`](server-system-variables.html#sysvar_net_buffer_length)每个 SQL 语句后的字节。在运行语句时，还会分配当前语句字符串的副本。

        每个连接线程都使用内存来计算语句摘要。服务器分配[`最大摘要长度`](server-system-variables.html#sysvar_max_digest_length)每个会话的字节数。看[第 27.10 节，“性能模式语句摘要和抽样”](performance-schema-statement-digests.html).

-   所有线程共享相同的基本内存。

-   当不再需要某个线程时，分配给它的内存将被释放并返回给系统，除非该线程返回到线程缓存中。在这种情况下，内存保持分配状态。

-   每个对表执行顺序扫描的请求都会分配一个读取缓冲区。这[`读取缓冲区大小`](server-system-variables.html#sysvar_read_buffer_size)系统变量确定缓冲区大小。

-   当以任意顺序读取行时（例如，在排序之后），可能会分配一个随机读取缓冲区以避免磁盘寻道。这[`read_rnd_buffer_size`](server-system-variables.html#sysvar_read_rnd_buffer_size)系统变量确定缓冲区大小。

-   所有连接都在一次执行中执行，大多数连接甚至可以在不使用临时表的情况下完成。大多数临时表是基于内存的哈希表。具有大行长度（计算为所有列长度的总和）或包含[`斑点`](blob.html)列存储在磁盘上。

-   大多数执行排序的请求根据结果集大小分配一个排序缓冲区和零到两个临时文件。看[第 B.3.3.5 节，“MySQL 存储临时文件的位置”](temporary-files.html).

-   几乎所有的解析和计算都是在线程本地和可重用的内存池中完成的。小项目不需要内存开销，从而避免了正常缓慢的内存分配和释放。仅为意外的大字符串分配内存。

-   对于每个表有[`斑点`](blob.html)列，缓冲区被动态扩大以读入更大的[`斑点`](blob.html)价值观。如果你扫描一个表，缓冲区会增长到最大的[`斑点`](blob.html)价值。

-   MySQL 需要用于表缓存的内存和描述符。所有正在使用的表的处理程序结构都保存在表缓存中，并以“先进先出”（FIFO）的方式进行管理。这[`table_open_cache`](server-system-variables.html#sysvar_table_open_cache)系统变量定义了初始表缓存大小；看[第 8.4.3.1 节，“MySQL 如何打开和关闭表”](table-cache.html).

    MySQL 还需要内存用于表定义缓存。这[`table_definition_cache`](server-system-variables.html#sysvar_table_definition_cache)系统变量定义可以存储在表定义缓存中的表定义的数量。如果使用大量的表，可以创建一个大的表定义缓存来加快表的打开速度。与表缓存不同，表定义缓存占用较少空间并且不使用文件描述符。

-   一种[`同花顺表`](flush.html#flush-tables)声明或[**mysqladmin 刷新表**](mysqladmin.html)命令一次关闭所有未使用的表，并在当前执行的线程完成时将所有正在使用的表标记为关闭。这有效地释放了大多数正在使用的内存。[`同花顺表`](flush.html#flush-tables)在所有表都关闭之前不会返回。

-   服务器将信息缓存在内存中，因为[`授予`](grant.html),[`创建用户`](create-user.html),[`创建服务器`](create-server.html)， 和[`安装插件`](install-plugin.html)陈述。这块内存没有被相应的释放[`撤销`](revoke.html),[`删除用户`](drop-user.html),[`删除服务器`](drop-server.html)， 和[`卸载插件`](uninstall-plugin.html)语句，因此对于执行导致缓存的语句的许多实例的服务器，缓存内存使用量会增加，除非它被释放[`刷新特权`](flush.html#flush-privileges).

-   在复制拓扑中，以下设置会影响内存使用，并且可以根据需要进行调整：

    -   这[`max_allowed_pa​​cket`](server-system-variables.html#sysvar_max_allowed_packet)复制源上的系统变量限制了源发送到其副本进行处理的最大消息大小。此设置默认为 64M。

    -   系统变量[`replica_pending_jobs_size_max`](replication-options-replica.html#sysvar_replica_pending_jobs_size_max)（来自 MySQL 8.0.26）或[`slave_pending_jobs_size_max`](replication-options-replica.html#sysvar_slave_pending_jobs_size_max)（在 MySQL 8.0.26 之前）在多线程副本上设置可用于保存等待处理的消息的最大内存量。此设置默认为 128M。内存仅在需要时分配，但如果您的复制拓扑有时会处理大型事务，则可能会使用它。这是一个软限制，可以处理更大的交易。

    -   这[`rpl_read_size`](replication-options-replica.html#sysvar_rpl_read_size)复制源或副本上的系统变量控制从二进制日志文件和中继日志文件读取的最小数据量（以字节为单位）。默认值为 8192 字节。为从二进制日志和中继日志文件读取的每个线程分配一个该值大小的缓冲区，包括源上的转储线程和副本上的协调器线程。

    -   这[`binlog_transaction_dependency_history_size`](replication-options-binary-log.html#sysvar_binlog_transaction_dependency_history_size)系统变量限制作为内存历史记录保存的行哈希数。

    -   这[`max_binlog_cache_size`](replication-options-binary-log.html#sysvar_max_binlog_cache_size)系统变量指定单个事务的内存使用上限。

    -   这[`max_binlog_stmt_cache_size`](replication-options-binary-log.html#sysvar_max_binlog_stmt_cache_size)系统变量指定语句缓存的内存使用上限。

**ps**和其他系统状态程序可能会报告[**mysqld**](mysqld.html)使用大量内存。这可能是由不同内存地址上的线程堆栈引起的。例如，Solaris 版本的**ps**将堆栈之间未使用的内存计算为已用内存。要验证这一点，请检查可用的交换`交换-s`.我们测试[**mysqld**](mysqld.html)有几个内存泄漏检测器（商业和开源），所以应该没有内存泄漏。

##### 监控 MySQL 内存使用情况

[](<>)[](<>)

下面的例子演示了如何使用[性能模式](performance-schema.html)和[系统架构](sys-schema.html)监控 MySQL 内存使用情况。

默认情况下，大多数性能模式内存检测是禁用的。仪器可以通过更新启用`已启用`性能模式的列[`setup_instruments`](performance-schema-setup-instruments-table.html)桌子。记忆仪器的名称形式为`记忆/*`代码区域`*/*`仪器名称`*`， 在哪里*`代码区域`*是一个值，例如`sql`要么`innodb`， 和*`仪器名称`*是仪器细节。

1.  要查看可用的 MySQL 内存工具，请查询 Performance Schema[`setup_instruments`](performance-schema-setup-instruments-table.html)桌子。以下查询为所有代码区域返回数百个内存工具。

    ```
    mysql> SELECT * FROM performance_schema.setup_instruments
           WHERE NAME LIKE '%memory%';
    ```

    您可以通过指定代码区域来缩小结果范围。例如，您可以将结果限制为`InnoDB`通过指定记忆工具`innodb`作为代码区域。

    ```
    mysql> SELECT * FROM performance_schema.setup_instruments
           WHERE NAME LIKE '%memory/innodb%';
    +-------------------------------------------+---------+-------+
    | NAME                                      | ENABLED | TIMED |
    +-------------------------------------------+---------+-------+
    | memory/innodb/adaptive hash index         | NO      | NO    |
    | 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/trx_sys_t::rw_trx_ids       | NO      | NO    |
    ...
    ```

    根据您的 MySQL 安装，代码区域可能包括`性能模式`,`sql`,`客户`,`innodb`,`米萨姆`,`csv`,`记忆`,`黑洞`,`档案`,`划分`， 和别的。

2.  要启用内存工具，请添加`性能模式工具`规则到您的 MySQL 配置文件。例如，要启用所有内存工具，请将此规则添加到您的配置文件并重新启动服务器：

    ```
    performance-schema-instrument='memory/%=COUNTED'
    ```

    笔记

    在启动时启用内存工具可确保计算启动时发生的内存分配。

    重启服务器后，`已启用`性能模式的列[`setup_instruments`](performance-schema-setup-instruments-table.html)表应该报告`是的`对于您启用的记忆工具。这`定时`列中的[`setup_instruments`](performance-schema-setup-instruments-table.html)由于内存操作不是定时的，因此内存仪器会忽略 table。

    ```
    mysql> SELECT * FROM performance_schema.setup_instruments
           WHERE NAME LIKE '%memory/innodb%';
    +-------------------------------------------+---------+-------+
    | NAME                                      | ENABLED | TIMED |
    +-------------------------------------------+---------+-------+
    | memory/innodb/adaptive hash index         | NO      | NO    |
    | 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/trx_sys_t::rw_trx_ids       | NO      | NO    |
    ...
    ```

3.  查询内存仪器数据。在这个例子中，内存仪器数据在 Performance Schema 中被查询[`memory_summary_global_by_event_name`](performance-schema-memory-summary-tables.html)表，其中汇总了数据`EVENT_NAME`.这`EVENT_NAME`是乐器的名称。

    以下查询返回内存数据`InnoDB`缓冲池。有关列说明，请参阅[第 27.12.20.10 节，“内存汇总表”](performance-schema-memory-summary-tables.html).

    ```
    mysql> SELECT * FROM performance_schema.memory_summary_global_by_event_name
           WHERE EVENT_NAME LIKE 'memory/innodb/buf_buf_pool'\G
                      EVENT_NAME: memory/innodb/buf_buf_pool
                     COUNT_ALLOC: 1
                      COUNT_FREE: 0
       SUM_NUMBER_OF_BYTES_ALLOC: 137428992
        SUM_NUMBER_OF_BYTES_FREE: 0
                  LOW_COUNT_USED: 0
              CURRENT_COUNT_USED: 1
                 HIGH_COUNT_USED: 1
        LOW_NUMBER_OF_BYTES_USED: 0
    CURRENT_NUMBER_OF_BYTES_USED: 137428992
       HIGH_NUMBER_OF_BYTES_USED: 137428992
    ```

    相同的基础数据可以使用[`系统`](sys-schema.html)图式[`memory_global_by_current_bytes`](sys-memory-global-by-current-bytes.html)表，显示全局服务器内的当前内存使用情况，按分配类型细分。

    ```
    mysql> SELECT * FROM sys.memory_global_by_current_bytes
           WHERE event_name LIKE 'memory/innodb/buf_buf_pool'\G
    *************************** 1. row ***************************
           event_name: memory/innodb/buf_buf_pool
        current_count: 1
        current_alloc: 131.06 MiB
    current_avg_alloc: 131.06 MiB
           high_count: 1
           high_alloc: 131.06 MiB
       high_avg_alloc: 131.06 MiB
    ```

    这[`系统`](sys-schema.html)架构查询聚合当前分配的内存（`当前分配`) 按代码区域：

    ```
    mysql> SELECT SUBSTRING_INDEX(event_name,'/',2) AS
           code_area, FORMAT_BYTES(SUM(current_alloc))
           AS current_alloc
           FROM sys.x$memory_global_by_current_bytes
           GROUP BY SUBSTRING_INDEX(event_name,'/',2)
           ORDER BY SUM(current_alloc) DESC;
    +---------------------------+---------------+
    | code_area                 | current_alloc |
    +---------------------------+---------------+
    | memory/innodb             | 843.24 MiB    |
    | memory/performance_schema | 81.29 MiB     |
    | memory/mysys              | 8.20 MiB      |
    | memory/sql                | 2.47 MiB      |
    | memory/memory             | 174.01 KiB    |
    | memory/myisam             | 46.53 KiB     |
    | memory/blackhole          | 512 bytes     |
    | memory/federated          | 512 bytes     |
    | memory/csv                | 512 bytes     |
    | memory/vio                | 496 bytes     |
    +---------------------------+---------------+
    ```

    笔记

    在 MySQL 8.0.16 之前，`sys.format_bytes()`用于[`FORMAT_BYTES()`](performance-schema-functions.html#function_format-bytes).

    有关更多信息[`系统`](sys-schema.html)架构，见[第 28 章，*MySQL 系统架构*](sys-schema.html).
