Documentation Home
MySQL 8.0 参考手册  / 第8章优化  / 8.12 优化MySQL服务器  / 8.12.3 优化内存使用  /  8.12.4.1 MySQL如何使用内存

8.12.4.1 MySQL如何使用内存

MySQL 分配缓冲区和高速缓存以提高数据库操作的性能。您可以通过增加某些缓存和缓冲区相关系统变量的值来提高 MySQL 性能。您还可以修改这些变量以在内存有限的系统上运行 MySQL。

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

  • InnoDB缓冲池是一个内存区域,用于保存InnoDB表、索引和其他辅助缓冲区的缓存数据 。为了提高大容量读取操作的效率,缓冲池被分成 可能包含多行的页面。为了缓存管理的效率,缓冲池被实现为页面链表;使用LRU算法的变体,很少使用的数据会从缓存中老化 。有关详细信息,请参阅第 14.5.1 节,“缓冲池”

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

    • InnoDBmalloc()在服务器启动时使用操作为整个缓冲池分配内存 。系统 innodb_buffer_pool_size 变量定义缓冲池大小。通常,推荐 innodb_buffer_pool_size 值为系统内存的 50% 到 75%。有关详细信息,请参阅 配置 InnoDB 缓冲池大小

    • 在具有大量内存的系统上,可以通过将缓冲池划分为多个 缓冲池实例来提高并发性。系统变量定义缓冲池实例的 innodb_buffer_pool_instances 数量。

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

    • 太大的缓冲池可能会由于内存竞争而导致交换。

  • 所有线程共享MyISAM 密钥缓冲区。key_buffer_size系统变量决定了它的大小 。

    对于服务器打开的每个MyISAM表,索引文件打开一次;数据文件为访问该表的每个并发运行的线程打开一次。对于每个并发线程,分配一个表结构、每列的列结构和一个大小的缓冲区 (其中是最大行长度,不包括 列)。一 列需要五到八个字节加上 数据的长度。存储引擎维护一个额外的行缓冲区供内部使用 。 3 * NNBLOBBLOBBLOBMyISAM

  • 系统myisam_use_mmap 变量可以设置为 1 以启用所有MyISAM表的内存映射。

  • 如果内部内存临时表变得太大(使用 tmp_table_sizemax_heap_table_size 系统变量确定),MySQL 会自动将表从内存格式转换为磁盘格式。磁盘临时表使用MyISAM存储引擎。您可以增加允许的临时表大小,如第 8.4.4 节,“MySQL 中的内部临时表使用”中所述。

    对于使用MEMORY显式创建的表CREATE TABLE,只有 max_heap_table_size 系统变量决定表可以增长到多大,并且没有转换为磁盘格式。

  • MySQL Performance Schema是一种用于在低级别监视 MySQL 服务器执行 的功能。出于性能原因,Performance Schema 的固定内存缓冲区在服务器启动时分配,并且在服务器运行时不会更改大小。

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

    连接缓冲区和结果缓冲区 net_buffer_length均以字节大小开始,但会根据需要动态扩大到 max_allowed_packet字节。结果缓冲区 net_buffer_length在每个 SQL 语句之后缩小为字节。语句运行时,还会分配当前语句字符串的副本。

    每个连接线程都使用内存来计算语句摘要。在 MySQL 5.6.24 及更高版本中,服务器 max_digest_length为每个会话分配字节。在 MySQL 5.6.24 之前,服务器为每个会话分配 1024 字节。请参阅 第 22.10 节,“性能模式语句摘要”

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

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

  • 每个对表执行顺序扫描的请求都会分配一个读取缓冲区。系统 read_buffer_size变量确定缓冲区大小。

  • 当以任意顺序读取行时(例如,在排序之后), 可以分配随机读取缓冲区以避免磁盘寻道。系统 read_rnd_buffer_size 变量确定缓冲区大小。

  • 所有连接都在一次传递中执行,大多数连接甚至可以在不使用临时表的情况下完成。大多数临时表都是基于内存的哈希表。具有较大行长度(计算为所有列长度的总和)或包含 BLOB列的临时表存储在磁盘上。

  • 大多数执行排序的请求都会根据结果集的大小分配一个排序缓冲区和零到两个临时文件。请参阅第 B.3.3.5 节,“MySQL 存储临时文件的位置”

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

  • 对于每个BLOB 包含列的表,缓冲区会动态扩大以读取更大的BLOB值。如果扫描表,缓冲区会增长到 BLOB最大值。

  • MySQL 需要表缓存的内存和描述符。所有正在使用的表的处理程序结构都保存在表缓存中,并按照先进先出 (FIFO) 的方式进行管理。系统 table_open_cache变量定义初始表缓存大小;参见 第 8.4.3.1 节,“MySQL 如何打开和关闭表”

    MySQL 还需要内存用于表定义缓存。table_definition_cache 系统变量定义.frm可以存储在表定义缓存中的表定义(来自文件)的 数量。如果你使用大量的表,你可以创建一个大的表定义缓存来加速表的打开。与表缓存不同,表定义缓存占用的空间更少,并且不使用文件描述符。

  • FLUSH TABLES语句或 mysqladmin flush-tables命令立即关闭所有未使用的表,并将所有使用中的表标记为在当前执行的线程完成时关闭 。这有效地释放了大部分正在使用的内存。FLUSH TABLES直到所有表都关闭后才返回。

  • 作为、 、 和 语句 的结果,服务器将信息缓存在内存中 GRANT。 此内存不会由相应 的 、 、 和 语句释放,因此对于执行许多导致缓存的语句实例的服务器,缓存内存使用量可能会增加,除非使用 释放它。 CREATE USERCREATE SERVERINSTALL PLUGINREVOKEDROP USERDROP SERVERUNINSTALL PLUGINFLUSH PRIVILEGES

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